diff options
Diffstat (limited to 'vendor/nix')
105 files changed, 0 insertions, 43284 deletions
diff --git a/vendor/nix/.cargo-checksum.json b/vendor/nix/.cargo-checksum.json deleted file mode 100644 index f4c932b88..000000000 --- a/vendor/nix/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"CHANGELOG.md":"8ee4e556e53d1b39400a48675d3ecff0bf27e419accab7ca3be76ab934289548","Cargo.toml":"2e6eff9170182f107188b8bc9802efd044ef47178afc7f138950ecff1c1ceb96","LICENSE":"66e3ee1fa7f909ad3c612d556f2a0cdabcd809ad6e66f3b0605015ac64841b70","README.md":"1ed9a0e26ae6e575b3262ae734dd02889455593b761ee62403ea5a64104f3c9c","src/dir.rs":"0280a2dc480bd913f24ed84fbe26569fa2e8eefa660e5ad7c21e05fc34c14d16","src/env.rs":"028bc5e20139ebba418a655a2978a53335dc7680bf1de43d2c8333dd72cfa5c4","src/errno.rs":"e55d075858e349d9afea9ce0480f7fb7ba4dccccf0694fd7b3280b918836203c","src/fcntl.rs":"ea8f43d8fec0b6c3b7d903333e4c1ce85611684a4afd561c55cfe4b61a979e94","src/features.rs":"5b4a0831e5f4b79a6f0e42ed052fd66c875da18959750be51e41fb59ac19feed","src/ifaddrs.rs":"377865eb48040d28c392a1aec0221320108e3392ea285d23405ae2cfa5c54b20","src/kmod.rs":"c818ced08d55ae36fdf82fa914ba856b688e37234d574d3faa37128211d512fb","src/lib.rs":"a62fac2ba7111157c5b64251f67f8a189f04bd587d5c80703454a596ea7ae5d9","src/macros.rs":"e23d7d8be22ef0bf9febaaf2739585453103607c0139bd3995a324e4a16d011e","src/mount/bsd.rs":"4cf35606a63d7ca41caac3b38f01e2b70c63e71978c0529f19fc79182629dbe0","src/mount/linux.rs":"6e5d61788dedf1ca4416c6c6a3a9c6c747f9352c26d863f4a1d4142e288584d6","src/mount/mod.rs":"ba9f60eb831224ab73bdd87e00e15d13b9ce9efb70b18bf8f3fe60406d522b3e","src/mqueue.rs":"ed0a189036b2437b5f7f7f1312fa545540b06ca72171b451d8bce42cc3627534","src/net/if_.rs":"b32a8a1f952de60d95e549779a5c673fd72aa665e86bfdfc8ec6badf3016b9b1","src/net/mod.rs":"577f70170e53d4a6de1abb70bf8f1031ec3e65c0e63ef5fcf05c907125e7ac17","src/poll.rs":"2fc1d144fb40db51811c6357b520ab7993529702d8f0d8060c903118ff4f7259","src/pty.rs":"27b4f76c23acf02542674017067fee74cdcac907338458700a1aa4d6f6a62e27","src/sched.rs":"403aa5ebed81910263d42a94717612b737550bf053227b7d90f1c8949188d919","src/sys/aio.rs":"ae091de8540c97da374a39e7d154c1b3ce50f41e6fc20a45c6b06eb838e74366","src/sys/epoll.rs":"28e22debf474d1b047e8044a00b354c25dab2fa125960f9f2f14cc34289fd5c9","src/sys/event.rs":"dbd8e84bccb813839295b0a336485783ef19548d2317931f0ceb5ee62f839a40","src/sys/eventfd.rs":"c8db8f5874726fdad289ad5e2603a7d71a1ae5a899dcde3a35d3edff8b498b7e","src/sys/inotify.rs":"5b4da774313afa9c28c3f92f9d07dce9bf4c8d044fd6a16f19480e79a19e808b","src/sys/ioctl/bsd.rs":"bbd02e30b0a78c1cb22777d9b00cfcbba9c68505cffc06118ac68474cf6fea39","src/sys/ioctl/linux.rs":"028181834d119b834bf399f2b8a6176cc57e75144693f28f32059d087d8c8018","src/sys/ioctl/mod.rs":"89b20579476b2e0254e0ecb1b41830cccd7027a22cbdb816a9d4ec3924842ac1","src/sys/memfd.rs":"f58d7fbe67c4b994832d72f5fbd59c136c8f1ae88ea8b0bc1c099db2d847ee6c","src/sys/mman.rs":"17df1bc34ba92bdd6bad1e11e4ef139998117f6c468c8f560421858f3cc899a5","src/sys/mod.rs":"baabf649f758ad4acce849ec1795dd4e4f9c6539e677bad5fa777300a4871dcb","src/sys/personality.rs":"aa89760c023bfec3fca5d8636f9eac9d337f5547933793ce6df7a0de97ae6ee1","src/sys/pthread.rs":"258cdf7ff0b61a4afa6d228109e4cb4fb88d859bb8dfe6c959d95130fb010906","src/sys/ptrace/bsd.rs":"4c590d8f023ff52f396f8b6f2150c08e5c9486d3088d9c173db33a70d616b800","src/sys/ptrace/linux.rs":"c82db3fb18aa97755f9ccb440a957cd46d664968a94045830c5d74d2d53bc19f","src/sys/ptrace/mod.rs":"e9e5d970097f5eafffba900959d4fdbf233bff9ed7f599fc9896bb44d86a57a4","src/sys/quota.rs":"02e698a25f0986fb43aa88689f3d3d8b9edc6ae48496ad02f7214fccaa493e00","src/sys/reboot.rs":"eacdf57694a6629fb05787e16450446102a62818274495f2ad4e445807d09221","src/sys/resource.rs":"d498d0c00fd30e35e1269a8902cb812014d813f63ec95364f8f59f1912ba5657","src/sys/select.rs":"65c39b129d3cc85b8ca026ff26dcf80c5639824f43715881c3c1bbb6bf0c8a60","src/sys/sendfile.rs":"7a62099f9771fecff49b9c11210341e3c1a4acf22f8dfb96d395e29421648676","src/sys/signal.rs":"c3e13a2edea54d190a4b051f62efc97953c00b5051a9fda0e39e3bc732a31939","src/sys/signalfd.rs":"583524434fd37143be3db37fa6f6cbd339f7946416f05b58a95e246947e5cc9d","src/sys/socket/addr.rs":"84df895052f59ec84774b189ffb285d2a37a9703af6c8310ae5040cca1a2583e","src/sys/socket/mod.rs":"6deb55438cad3606385303f036b0efd842dfd759fba93611911f5a4f2613c9dc","src/sys/socket/sockopt.rs":"ed1f920364bfe88bbe6eaeeefb27a63bfcdd7d67604aca2f03e22f2b502df55a","src/sys/stat.rs":"337dea8d55d6177dc85b3235b40b8a3e81af7f4a6e2806a0b2f730bec5424350","src/sys/statfs.rs":"17103659a85279bac046c69cb3b22bf2c11c2492cffb0edfa4c3b233d161a2f2","src/sys/statvfs.rs":"f81e3900ef90d62e7eceaf1b6ff8dcfd965466714c033eb4717687f692171f48","src/sys/sysinfo.rs":"b4519b1ca091c9dbe94d2a6fd6304944bf3df5626973d2c6884022559706f0d9","src/sys/termios.rs":"7923f9846a8122096b6b1cd240d3618b876ce500a751ac434954d172e2e85745","src/sys/time.rs":"9026033b60a5ccc95b70424aef043c8c748722e2ea8c7c86366ecd4585b651a0","src/sys/timer.rs":"8c10f0e7cfac857ad00460be30bc68b957909cc9296e70718d3b5d4a0babafde","src/sys/timerfd.rs":"ef7c48aefdcfac13316eeddbef5da04cf12e9f574b8d9f43402c02b6b8db86b3","src/sys/uio.rs":"e1d59ccbee9d46c65d3aa8c36aa3a3222539beea0d20163a8b707d08fca14e09","src/sys/utsname.rs":"0cdda0cc111caaa0e4ebe2d4588bdc825d878e5bcb7a9136073b15f87a20e11f","src/sys/wait.rs":"cc70d2d9b880ff6c48577a479c209af6127067bc013a90ee22538e4dfad7d2b4","src/time.rs":"d4e0872361a57810837f5bd790cbca3a2b9db1ac4694a3c52d1564ad3532d3be","src/ucontext.rs":"b8f2e04757a9c2bc38c3b1e259d3a013da8a730fe9bfbe5487637395681b43d3","src/unistd.rs":"e19be456124731c5b93aef92ed72a7c4c9092e28db0649814ba3fcc1f0d620fa","test/common/mod.rs":"1d7e28e3635754664cd056f3a1079232ff5c118df619e1d0551a9972eb0b3cd6","test/sys/mod.rs":"87b2891d83067ff21f72b8ff7fde3019dc45b6877282ac278b6da151de45c7a7","test/sys/test_aio.rs":"4dac9f716f852f1f438f78d6e64bf041e6fd316bf15dcb27afffaf0894bdefa6","test/sys/test_aio_drop.rs":"614070155fa16a979b7341d001639c5ce24a1d6f632c3abce45a5a6d49c4039b","test/sys/test_epoll.rs":"ffe95e36c79e37426ef8e8ca3b137b7f35ea0333ce666a20a4b7878db17680e9","test/sys/test_inotify.rs":"a141b9a995892547b51ceeb6761a70a6b86d37e8f38d13ea2c497b81b4b0f49f","test/sys/test_ioctl.rs":"00ccc5afb665e533a0a4b6d6a6be438bcaea19fce335390feef4e91d17b3036c","test/sys/test_mman.rs":"2b4161964c9204b74659028b0f89a88f4e3bcc9886137a3039737cd91d2698cb","test/sys/test_pthread.rs":"ace36a2f5587f1874854281b4fd84e4e4d892a1e3c5cc38ced57975739522ad6","test/sys/test_ptrace.rs":"0385eebc8b1b8c72f655b745769decd9143ad83018198375982da0896310456b","test/sys/test_select.rs":"54cea1c34ad28d5770a613c1c3cbc3b1064b22037ec2b9d3fcd422d3be9e60a7","test/sys/test_signal.rs":"acc9941227bd3e2afad323613c2b8c83902ed0486d3745fd72704f395924f1e4","test/sys/test_signalfd.rs":"0e1060143e2612c490bc3d0168d0bbb042ef55e3f1d91d2578b9e42e4310a14d","test/sys/test_socket.rs":"d2df1001f9a0b2dac0b88051a67c3868bb216e72e4da4eecd11c4448b9fa4b40","test/sys/test_sockopt.rs":"4465f22f718442f3f7b502e052dad02b93cebfa3b71fa55ff4f25fb02534acab","test/sys/test_stat.rs":"6630a28217fd708bb84cd4f7e7101836b74f2420f9888923fdab664ccc331c1d","test/sys/test_sysinfo.rs":"ffd49bc96375914a2c4a4a59730cae8072f85771e2c4a80d3403df38d967e272","test/sys/test_termios.rs":"e5bcef10c84bd7583d600d5601835bcb3cfc88781cb283ab0185bbef5faf4327","test/sys/test_timerfd.rs":"cfed3abf58118611d08f6985251a7739cff67108e11214222a1d2394a3a026ce","test/sys/test_uio.rs":"32656bd0a5699e4d019aa928edf104637937179782914a82d50d37226e84c421","test/sys/test_wait.rs":"6fd59fffeeb09ff620c359baefd062ba777598982b6cb001ccc07b6bc7605493","test/test.rs":"11f40b0718ddd1a150cb9e703d56d0b2a9462306505a2245ddf273a2011f48b5","test/test_clearenv.rs":"45ca548035b3c20ec87314715feaba2be973709a635d85b8cde46fd1d9f1ecd4","test/test_dir.rs":"ae3c11c58cb06da6557aa2a839c6653c54cd7724283fffe9df5a5d3feabdd89a","test/test_fcntl.rs":"71dcb87f7b04d78fc62937ba46cb7f0f1f2dbb330b63a996ea2e8ec9056b98a9","test/test_kmod/hello_mod/Makefile":"0219f7bce0603f97d997fb377ca071966c90333ecc665e78a54dfeb97a9c811b","test/test_kmod/hello_mod/hello.c":"bcac6b19c5bd807e1f3878c15e426acc85785a8ade9840c3bb4d068635c9188c","test/test_kmod/mod.rs":"b4ae25841c2f06f32de9f1acd8230eeccd7095721302ebe78ad454e4e4f9c783","test/test_mount.rs":"6dd242b6e23c9c39e1a75612bbea62573898818ab374c3c032c2cdb97033554d","test/test_mq.rs":"136071f24131aac0e65d5f29ac18e3806641dfae1164813f5570c0e3a6f70553","test/test_net.rs":"f2912327ebb2a3d37e6cff02a5ac3106cf889cc5c74404db4ef0034059ba26f1","test/test_nix_path.rs":"01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b","test/test_nmount.rs":"d6c112547bb80968170b5497cda4b6cbf69dabec6f51d494bd52298995ceff18","test/test_poll.rs":"3e0b8f0397ba080785c61a3bfc3d637bc87f324bc4e52b5f1bf3ca0d32dbc9fe","test/test_pty.rs":"b26238a0783746cb31880e11eebc1913149be999ce75fbc2d6677bdd1e2731b2","test/test_ptymaster_drop.rs":"ae63c815f5028ddc67d194e86559483018ab1816316bdb917f40cee9364fd8a5","test/test_resource.rs":"40aef790ab745cec31a4b333d2ca406b462aa9bdf4a6d3756371e498b8d51e9a","test/test_sched.rs":"c4579bd376fab8816e63b07fa9ace31dc08e63ebb7c855a2c450698090d1d1e8","test/test_sendfile.rs":"bb41b4f3621b518e397d3a5b5ad3c5dcef3fe506afe516eab7572fbab92b77e3","test/test_stat.rs":"c407ca47a5258750076d041afad2f6add4c3563be36628bde1c5b314f5d0765d","test/test_time.rs":"f7a21b1e279e60e84909d5dadda97ded66d3326b131fe317badf9af0a1b50335","test/test_timer.rs":"3ae20d364f075d2811f3ff94eda9886682cc21d8807656007d2464fe36d1e361","test/test_unistd.rs":"20a00be4fbe26302ea5fe50ce25b99265dc763db138663d6aa1d7ac729a1d292"},"package":"bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a"}
\ No newline at end of file diff --git a/vendor/nix/CHANGELOG.md b/vendor/nix/CHANGELOG.md deleted file mode 100644 index 283cb86a3..000000000 --- a/vendor/nix/CHANGELOG.md +++ /dev/null @@ -1,1585 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -This project adheres to [Semantic Versioning](https://semver.org/). - -## [0.26.2] - 2023-01-18 -### Fixed -- Fix `SockaddrIn6` bug that was swapping flowinfo and scope_id byte ordering. - ([#1964](https://github.com/nix-rust/nix/pull/1964)) - -## [0.26.1] - 2022-11-29 -### Fixed -- Fix UB with `sys::socket::sockopt::SockType` using `SOCK_PACKET`. - ([#1821](https://github.com/nix-rust/nix/pull/1821)) - -## [0.26.0] - 2022-11-29 -### Added - -- Added `SockaddrStorage::{as_unix_addr, as_unix_addr_mut}` - ([#1871](https://github.com/nix-rust/nix/pull/1871)) -- Added `MntFlags` and `unmount` on all of the BSDs. -- Added `any()` and `all()` to `poll::PollFd`. - ([#1877](https://github.com/nix-rust/nix/pull/1877)) -- Add `MntFlags` and `unmount` on all of the BSDs. - ([#1849](https://github.com/nix-rust/nix/pull/1849)) -- Added a `Statfs::flags` method. - ([#1849](https://github.com/nix-rust/nix/pull/1849)) -- Added `NSFS_MAGIC` FsType on Linux and Android. - ([#1829](https://github.com/nix-rust/nix/pull/1829)) -- Added `sched_getcpu` on platforms that support it. - ([#1825](https://github.com/nix-rust/nix/pull/1825)) -- Added `sched_getaffinity` and `sched_setaffinity` on FreeBSD. - ([#1804](https://github.com/nix-rust/nix/pull/1804)) -- Added `line_discipline` field to `Termios` on Linux, Android and Haiku - ([#1805](https://github.com/nix-rust/nix/pull/1805)) -- Expose the memfd module on FreeBSD (memfd was added in FreeBSD 13) - ([#1808](https://github.com/nix-rust/nix/pull/1808)) -- Added `domainname` field of `UtsName` on Android and Linux - ([#1817](https://github.com/nix-rust/nix/pull/1817)) -- Re-export `RLIM_INFINITY` from `libc` - ([#1831](https://github.com/nix-rust/nix/pull/1831)) -- Added `syncfs(2)` on Linux - ([#1833](https://github.com/nix-rust/nix/pull/1833)) -- Added `faccessat(2)` on illumos - ([#1841](https://github.com/nix-rust/nix/pull/1841)) -- Added `eaccess()` on FreeBSD, DragonFly and Linux (glibc and musl). - ([#1842](https://github.com/nix-rust/nix/pull/1842)) -- Added `IP_TOS` `SO_PRIORITY` and `IPV6_TCLASS` sockopts for Linux - ([#1853](https://github.com/nix-rust/nix/pull/1853)) -- Added `new_unnamed` and `is_unnamed` for `UnixAddr` on Linux and Android. - ([#1857](https://github.com/nix-rust/nix/pull/1857)) -- Added `SockProtocol::Raw` for raw sockets - ([#1848](https://github.com/nix-rust/nix/pull/1848)) -- added `IP_MTU` (`IpMtu`) `IPPROTO_IP` sockopt on Linux and Android. - ([#1865](https://github.com/nix-rust/nix/pull/1865)) - -### Changed - -- The MSRV is now 1.56.1 - ([#1792](https://github.com/nix-rust/nix/pull/1792)) -- The `addr` argument of `sys::mman::mmap` is now of type `Option<NonZeroUsize>`. - ([#1870](https://github.com/nix-rust/nix/pull/1870)) -- The `length` argument of `sys::mman::mmap` is now of type `NonZeroUsize`. - ([#1873](https://github.com/nix-rust/nix/pull/1873)) - -### Fixed - -- Fixed using `SockaddrStorage` to store a Unix-domain socket address on Linux. - ([#1871](https://github.com/nix-rust/nix/pull/1871)) -- Fix microsecond calculation for `TimeSpec`. - ([#1801](https://github.com/nix-rust/nix/pull/1801)) -- Fix `User::from_name` and `Group::from_name` panicking - when given a name containing a nul. - ([#1815](https://github.com/nix-rust/nix/pull/1815)) -- Fix `User::from_uid` and `User::from_name` crash on Android platform. - ([#1824](https://github.com/nix-rust/nix/pull/1824)) -- Workaround XNU bug causing netmasks returned by `getifaddrs` to misbehave. - ([#1788](https://github.com/nix-rust/nix/pull/1788)) - -### Removed - -- Removed deprecated error constants and conversions. - ([#1860](https://github.com/nix-rust/nix/pull/1860)) - -## [0.25.0] - 2022-08-13 -### Added - -- Added `faccessat` - ([#1780](https://github.com/nix-rust/nix/pull/1780)) -- Added `memfd` on Android. - (#[1773](https://github.com/nix-rust/nix/pull/1773)) -- Added `ETH_P_ALL` to `SockProtocol` enum - (#[1768](https://github.com/nix-rust/nix/pull/1768)) -- Added four non-standard Linux `SysconfVar` variants - (#[1761](https://github.com/nix-rust/nix/pull/1761)) -- Added const constructors for `TimeSpec` and `TimeVal` - (#[1760](https://github.com/nix-rust/nix/pull/1760)) -- Added `chflags`. - (#[1758](https://github.com/nix-rust/nix/pull/1758)) -- Added `aio_writev` and `aio_readv`. - (#[1713](https://github.com/nix-rust/nix/pull/1713)) -- impl `From<uid_t>` for `Uid` and `From<gid_t>` for `Gid` - (#[1727](https://github.com/nix-rust/nix/pull/1727)) -- impl `From<SockaddrIn>` for `std::net::SocketAddrV4` and - impl `From<SockaddrIn6>` for `std::net::SocketAddrV6`. - (#[1711](https://github.com/nix-rust/nix/pull/1711)) -- Added support for the `x86_64-unknown-haiku` target. - (#[1703](https://github.com/nix-rust/nix/pull/1703)) -- Added `ptrace::read_user` and `ptrace::write_user` for Linux. - (#[1697](https://github.com/nix-rust/nix/pull/1697)) -- Added `getrusage` and helper types `UsageWho` and `Usage` - (#[1747](https://github.com/nix-rust/nix/pull/1747)) -- Added the `DontRoute` SockOpt - (#[1752](https://github.com/nix-rust/nix/pull/1752)) -- Added `signal::SigSet::from_sigset_t_unchecked()`. - (#[1741](https://github.com/nix-rust/nix/pull/1741)) -- Added the `Ipv4OrigDstAddr` sockopt and control message. - (#[1772](https://github.com/nix-rust/nix/pull/1772)) -- Added the `Ipv6OrigDstAddr` sockopt and control message. - (#[1772](https://github.com/nix-rust/nix/pull/1772)) -- Added the `Ipv4SendSrcAddr` control message. - (#[1776](https://github.com/nix-rust/nix/pull/1776)) - -### Changed - -- Reimplemented sendmmsg/recvmmsg to avoid allocations and with better API - (#[1744](https://github.com/nix-rust/nix/pull/1744)) - -- Rewrote the aio module. The new module: - * Does more type checking at compile time rather than runtime. - * Gives the caller control over whether and when to `Box` an aio operation. - * Changes the type of the `priority` arguments to `i32`. - * Changes the return type of `aio_return` to `usize`. - (#[1713](https://github.com/nix-rust/nix/pull/1713)) -- `nix::poll::ppoll`: `sigmask` parameter is now optional. - (#[1739](https://github.com/nix-rust/nix/pull/1739)) -- Changed `gethostname` to return an owned `OsString`. - (#[1745](https://github.com/nix-rust/nix/pull/1745)) -- `signal:SigSet` is now marked as `repr(transparent)`. - (#[1741](https://github.com/nix-rust/nix/pull/1741)) - -### Removed - -- Removed support for resubmitting partially complete `lio_listio` operations. - It was too complicated, and didn't fit Nix's theme of zero-cost abstractions. - Instead, it can be reimplemented downstream. - (#[1713](https://github.com/nix-rust/nix/pull/1713)) - -## [0.24.2] - 2022-07-17 -### Fixed - -- Fixed buffer overflow in `nix::sys::socket::recvfrom`. - (#[1763](https://github.com/nix-rust/nix/pull/1763)) -- Enabled `SockaddrStorage::{as_link_addr, as_link_addr_mut}` for Linux-like - operating systems. - (#[1729](https://github.com/nix-rust/nix/pull/1729)) -- Fixed `SockaddrLike::from_raw` implementations for `VsockAddr` and - `SysControlAddr`. - (#[1736](https://github.com/nix-rust/nix/pull/1736)) - -## [0.24.1] - 2022-04-22 -### Fixed - -- Fixed `UnixAddr::size` on Linux-based OSes. - (#[1702](https://github.com/nix-rust/nix/pull/1702)) - -## [0.24.0] - 2022-04-21 -### Added - -- Added fine-grained features flags. Most Nix functionality can now be - conditionally enabled. By default, all features are enabled. - (#[1611](https://github.com/nix-rust/nix/pull/1611)) -- Added statfs FS type magic constants for `target_os = "android"` - and synced constants with libc v0.2.121. - (#[1690](https://github.com/nix-rust/nix/pull/1690)) -- Added `fexecve` on DragonFly. - (#[1577](https://github.com/nix-rust/nix/pull/1577)) -- `sys::uio::IoVec` is now `Send` and `Sync` - (#[1582](https://github.com/nix-rust/nix/pull/1582)) -- Added `EPOLLEXCLUSIVE` on Android. - (#[1567](https://github.com/nix-rust/nix/pull/1567)) -- Added `fdatasync` for FreeBSD, Fuchsia, NetBSD, and OpenBSD. - (#[1581](https://github.com/nix-rust/nix/pull/1581)) -- Added `sched_setaffinity` and `sched_getaffinity` on DragonFly. - (#[1537](https://github.com/nix-rust/nix/pull/1537)) -- Added `posix_fallocate` on DragonFly. - (#[1621](https://github.com/nix-rust/nix/pull/1621)) -- Added `SO_TIMESTAMPING` support - (#[1547](https://github.com/nix-rust/nix/pull/1547)) -- Added getter methods to `MqAttr` struct - (#[1619](https://github.com/nix-rust/nix/pull/1619)) -- Added the `TxTime` sockopt and control message. - (#[1564](https://github.com/nix-rust/nix/pull/1564)) -- Added POSIX per-process timer support - (#[1622](https://github.com/nix-rust/nix/pull/1622)) -- Added `sendfile` on DragonFly. - (#[1615](https://github.com/nix-rust/nix/pull/1615)) -- Added `UMOUNT_NOFOLLOW`, `FUSE_SUPER_MAGIC` on Linux. - (#[1634](https://github.com/nix-rust/nix/pull/1634)) -- Added `getresuid`, `setresuid`, `getresgid`, and `setresgid` on DragonFly, FreeBSD, and OpenBSD. - (#[1628](https://github.com/nix-rust/nix/pull/1628)) -- Added `MAP_FIXED_NOREPLACE` on Linux. - (#[1636](https://github.com/nix-rust/nix/pull/1636)) -- Added `fspacectl` on FreeBSD - (#[1640](https://github.com/nix-rust/nix/pull/1640)) -- Added `accept4` on DragonFly, Emscripten, Fuchsia, Illumos, and NetBSD. - (#[1654](https://github.com/nix-rust/nix/pull/1654)) -- Added `AsRawFd` implementation on `OwningIter`. - (#[1563](https://github.com/nix-rust/nix/pull/1563)) -- Added `process_vm_readv` and `process_vm_writev` on Android. - (#[1557](https://github.com/nix-rust/nix/pull/1557)) -- Added `nix::uncontext` module on s390x. - (#[1662](https://github.com/nix-rust/nix/pull/1662)) -- Implemented `Extend`, `FromIterator`, and `IntoIterator` for `SigSet` and - added `SigSet::iter` and `SigSetIter`. - (#[1553](https://github.com/nix-rust/nix/pull/1553)) -- Added `ENOTRECOVERABLE` and `EOWNERDEAD` error codes on DragonFly. - (#[1665](https://github.com/nix-rust/nix/pull/1665)) -- Implemented `Read` and `Write` for `&PtyMaster` - (#[1664](https://github.com/nix-rust/nix/pull/1664)) -- Added `MSG_NOSIGNAL` for Android, Dragonfly, FreeBSD, Fuchsia, Haiku, Illumos, Linux, NetBSD, OpenBSD and Solaris. - (#[1670](https://github.com/nix-rust/nix/pull/1670)) -- Added `waitid`. - (#[1584](https://github.com/nix-rust/nix/pull/1584)) -- Added `Ipv6DontFrag` for android, iOS, linux and macOS. -- Added `IpDontFrag` for iOS, macOS. - (#[1692](https://github.com/nix-rust/nix/pull/1692)) - -### Changed - -- `mqueue` functions now operate on a distinct type, `nix::mqueue::MqdT`. - Accessors take this type by reference, not by value. - (#[1639](https://github.com/nix-rust/nix/pull/1639)) -- Removed `SigSet::extend` in favor of `<SigSet as Extend<Signal>>::extend`. - Because of this change, you now need `use std::iter::Extend` to call `extend` - on a `SigSet`. - (#[1553](https://github.com/nix-rust/nix/pull/1553)) -- Removed the the `PATH_MAX` restriction from APIs accepting paths. Paths - will now be allocated on the heap if they are too long. In addition, large - instruction count improvements (~30x) were made to path handling. - (#[1656](https://github.com/nix-rust/nix/pull/1656)) -- Changed `getrlimit` and `setrlimit` to use `rlim_t` directly - instead of `Option<rlim_t>`. - (#[1668](https://github.com/nix-rust/nix/pull/1668)) -- Deprecated `InetAddr` and `SockAddr` in favor of `SockaddrIn`, `SockaddrIn6`, - and `SockaddrStorage`. - (#[1684](https://github.com/nix-rust/nix/pull/1684)) -- Deprecated `IpAddr`, `Ipv4Addr`, and `Ipv6Addr` in favor of their equivalents - from the standard library. - (#[1685](https://github.com/nix-rust/nix/pull/1685)) -- `uname` now returns a `Result<UtsName>` instead of just a `UtsName` and - ignoring failures from libc. And getters on the `UtsName` struct now return - an `&OsStr` instead of `&str`. - (#[1672](https://github.com/nix-rust/nix/pull/1672)) -- Replaced `IoVec` with `IoSlice` and `IoSliceMut`, and replaced `IoVec::from_slice` with - `IoSlice::new`. (#[1643](https://github.com/nix-rust/nix/pull/1643)) - -### Fixed - -- `InetAddr::from_std` now sets the `sin_len`/`sin6_len` fields on the BSDs. - (#[1642](https://github.com/nix-rust/nix/pull/1642)) -- Fixed a panic in `LinkAddr::addr`. That function now returns an `Option`. - (#[1675](https://github.com/nix-rust/nix/pull/1675)) - (#[1677](https://github.com/nix-rust/nix/pull/1677)) - -### Removed - -- Removed public access to the inner fields of `NetlinkAddr`, `AlgAddr`, - `SysControlAddr`, `LinkAddr`, and `VsockAddr`. - (#[1614](https://github.com/nix-rust/nix/pull/1614)) -- Removed `EventFlag::EV_SYSFLAG`. - (#[1635](https://github.com/nix-rust/nix/pull/1635)) - -## [0.23.1] - 2021-12-16 - -### Changed - -- Relaxed the bitflags requirement from 1.3.1 to 1.1. This partially reverts - #1492. From now on, the MSRV is not guaranteed to work with all versions of - all dependencies, just with some version of all dependencies. - (#[1607](https://github.com/nix-rust/nix/pull/1607)) - -### Fixed - -- Fixed soundness issues in `FdSet::insert`, `FdSet::remove`, and - `FdSet::contains` involving file descriptors outside of the range - `0..FD_SETSIZE`. - (#[1575](https://github.com/nix-rust/nix/pull/1575)) - -## [0.23.0] - 2021-09-28 -### Added - -- Added the `LocalPeerCred` sockopt. - (#[1482](https://github.com/nix-rust/nix/pull/1482)) -- Added `TimeSpec::from_duration` and `TimeSpec::from_timespec` - (#[1465](https://github.com/nix-rust/nix/pull/1465)) -- Added `IPV6_V6ONLY` sockopt. - (#[1470](https://github.com/nix-rust/nix/pull/1470)) -- Added `impl From<User> for libc::passwd` trait implementation to convert a `User` - into a `libc::passwd`. Consumes the `User` struct to give ownership over - the member pointers. - (#[1471](https://github.com/nix-rust/nix/pull/1471)) -- Added `pthread_kill`. - (#[1472](https://github.com/nix-rust/nix/pull/1472)) -- Added `mknodat`. - (#[1473](https://github.com/nix-rust/nix/pull/1473)) -- Added `setrlimit` and `getrlimit`. - (#[1302](https://github.com/nix-rust/nix/pull/1302)) -- Added `ptrace::interrupt` method for platforms that support `PTRACE_INTERRUPT` - (#[1422](https://github.com/nix-rust/nix/pull/1422)) -- Added `IP6T_SO_ORIGINAL_DST` sockopt. - (#[1490](https://github.com/nix-rust/nix/pull/1490)) -- Added the `PTRACE_EVENT_STOP` variant to the `sys::ptrace::Event` enum - (#[1335](https://github.com/nix-rust/nix/pull/1335)) -- Exposed `SockAddr::from_raw_sockaddr` - (#[1447](https://github.com/nix-rust/nix/pull/1447)) -- Added `TcpRepair` - (#[1503](https://github.com/nix-rust/nix/pull/1503)) -- Enabled `pwritev` and `preadv` for more operating systems. - (#[1511](https://github.com/nix-rust/nix/pull/1511)) -- Added support for `TCP_MAXSEG` TCP Maximum Segment Size socket options - (#[1292](https://github.com/nix-rust/nix/pull/1292)) -- Added `Ipv4RecvErr` and `Ipv6RecvErr` sockopts and associated control messages. - (#[1514](https://github.com/nix-rust/nix/pull/1514)) -- Added `AsRawFd` implementation on `PollFd`. - (#[1516](https://github.com/nix-rust/nix/pull/1516)) -- Added `Ipv4Ttl` and `Ipv6Ttl` sockopts. - (#[1515](https://github.com/nix-rust/nix/pull/1515)) -- Added `MAP_EXCL`, `MAP_ALIGNED_SUPER`, and `MAP_CONCEAL` mmap flags, and - exposed `MAP_ANONYMOUS` for all operating systems. - (#[1522](https://github.com/nix-rust/nix/pull/1522)) - (#[1525](https://github.com/nix-rust/nix/pull/1525)) - (#[1531](https://github.com/nix-rust/nix/pull/1531)) - (#[1534](https://github.com/nix-rust/nix/pull/1534)) -- Added read/write accessors for 'events' on `PollFd`. - (#[1517](https://github.com/nix-rust/nix/pull/1517)) - -### Changed - -- `FdSet::{contains, highest, fds}` no longer require a mutable reference. - (#[1464](https://github.com/nix-rust/nix/pull/1464)) -- `User::gecos` and corresponding `libc::passwd::pw_gecos` are supported on - 64-bit Android, change conditional compilation to include the field in - 64-bit Android builds - (#[1471](https://github.com/nix-rust/nix/pull/1471)) -- `eventfd`s are supported on Android, change conditional compilation to - include `sys::eventfd::eventfd` and `sys::eventfd::EfdFlags`for Android - builds. - (#[1481](https://github.com/nix-rust/nix/pull/1481)) -- Most enums that come from C, for example `Errno`, are now marked as - `#[non_exhaustive]`. - (#[1474](https://github.com/nix-rust/nix/pull/1474)) -- Many more functions, mostly contructors, are now `const`. - (#[1476](https://github.com/nix-rust/nix/pull/1476)) - (#[1492](https://github.com/nix-rust/nix/pull/1492)) -- `sys::event::KEvent::filter` now returns a `Result` instead of being - infalliable. The only cases where it will now return an error are cases - where it previously would've had undefined behavior. - (#[1484](https://github.com/nix-rust/nix/pull/1484)) -- Minimum supported Rust version is now 1.46.0. - ([#1492](https://github.com/nix-rust/nix/pull/1492)) -- Rework `UnixAddr` to encapsulate internals better in order to fix soundness - issues. No longer allows creating a `UnixAddr` from a raw `sockaddr_un`. - ([#1496](https://github.com/nix-rust/nix/pull/1496)) -- Raised bitflags to 1.3.0 and the MSRV to 1.46.0. - ([#1492](https://github.com/nix-rust/nix/pull/1492)) - -### Fixed - -- `posix_fadvise` now returns errors in the conventional way, rather than as a - non-zero value in `Ok()`. - (#[1538](https://github.com/nix-rust/nix/pull/1538)) -- Added more errno definitions for better backwards compatibility with - Nix 0.21.0. - (#[1467](https://github.com/nix-rust/nix/pull/1467)) -- Fixed potential undefined behavior in `Signal::try_from` on some platforms. - (#[1484](https://github.com/nix-rust/nix/pull/1484)) -- Fixed buffer overflow in `unistd::getgrouplist`. - (#[1545](https://github.com/nix-rust/nix/pull/1545)) - - -### Removed - -- Removed a couple of termios constants on redox that were never actually - supported. - (#[1483](https://github.com/nix-rust/nix/pull/1483)) -- Removed `nix::sys::signal::NSIG`. It was of dubious utility, and not correct - for all platforms. - (#[1484](https://github.com/nix-rust/nix/pull/1484)) -- Removed support for 32-bit Apple targets, since they've been dropped by both - Rustc and Xcode. - (#[1492](https://github.com/nix-rust/nix/pull/1492)) -- Deprecated `SockAddr/InetAddr::to_str` in favor of `ToString::to_string` - (#[1495](https://github.com/nix-rust/nix/pull/1495)) -- Removed `SigevNotify` on OpenBSD and Redox. - (#[1511](https://github.com/nix-rust/nix/pull/1511)) - -## [0.22.3] - 22 January 2022 -### Changed -- Relaxed the bitflags requirement from 1.3.1 to 1.1. This partially reverts - #1492. From now on, the MSRV is not guaranteed to work with all versions of - all dependencies, just with some version of all dependencies. - (#[1607](https://github.com/nix-rust/nix/pull/1607)) - -## [0.22.2] - 28 September 2021 -### Fixed -- Fixed buffer overflow in `unistd::getgrouplist`. - (#[1545](https://github.com/nix-rust/nix/pull/1545)) -- Added more errno definitions for better backwards compatibility with - Nix 0.21.0. - (#[1467](https://github.com/nix-rust/nix/pull/1467)) - -## [0.22.1] - 13 August 2021 -### Fixed -- Locked bitflags to < 1.3.0 to fix the build with rust < 1.46.0. - -### Removed -- Removed a couple of termios constants on redox that were never actually - supported. - (#[1483](https://github.com/nix-rust/nix/pull/1483)) - -## [0.22.0] - 9 July 2021 -### Added -- Added `if_nameindex` (#[1445](https://github.com/nix-rust/nix/pull/1445)) -- Added `nmount` for FreeBSD. - (#[1453](https://github.com/nix-rust/nix/pull/1453)) -- Added `IpFreebind` socket option (sockopt) on Linux, Fuchsia and Android. - (#[1456](https://github.com/nix-rust/nix/pull/1456)) -- Added `TcpUserTimeout` socket option (sockopt) on Linux and Fuchsia. - (#[1457](https://github.com/nix-rust/nix/pull/1457)) -- Added `renameat2` for Linux - (#[1458](https://github.com/nix-rust/nix/pull/1458)) -- Added `RxqOvfl` support on Linux, Fuchsia and Android. - (#[1455](https://github.com/nix-rust/nix/pull/1455)) - -### Changed -- `ptsname_r` now returns a lossily-converted string in the event of bad UTF, - just like `ptsname`. - ([#1446](https://github.com/nix-rust/nix/pull/1446)) -- Nix's error type is now a simple wrapper around the platform's Errno. This - means it is now `Into<std::io::Error>`. It's also `Clone`, `Copy`, `Eq`, and - has a small fixed size. It also requires less typing. For example, the old - enum variant `nix::Error::Sys(nix::errno::Errno::EINVAL)` is now simply - `nix::Error::EINVAL`. - ([#1446](https://github.com/nix-rust/nix/pull/1446)) - -## [0.21.2] - 29 September 2021 -### Fixed -- Fixed buffer overflow in `unistd::getgrouplist`. - (#[1545](https://github.com/nix-rust/nix/pull/1545)) - -## [0.21.1] - 13 August 2021 -### Fixed -- Locked bitflags to < 1.3.0 to fix the build with rust < 1.46.0. - -### Removed -- Removed a couple of termios constants on redox that were never actually - supported. - (#[1483](https://github.com/nix-rust/nix/pull/1483)) - -## [0.21.0] - 31 May 2021 -### Added -- Added `getresuid` and `getresgid` - (#[1430](https://github.com/nix-rust/nix/pull/1430)) -- Added TIMESTAMPNS support for linux - (#[1402](https://github.com/nix-rust/nix/pull/1402)) -- Added `sendfile64` (#[1439](https://github.com/nix-rust/nix/pull/1439)) -- Added `MS_LAZYTIME` to `MsFlags` - (#[1437](https://github.com/nix-rust/nix/pull/1437)) - -### Changed -- Made `forkpty` unsafe, like `fork` - (#[1390](https://github.com/nix-rust/nix/pull/1390)) -- Made `Uid`, `Gid` and `Pid` methods `from_raw` and `as_raw` a `const fn` - (#[1429](https://github.com/nix-rust/nix/pull/1429)) -- Made `Uid::is_root` a `const fn` - (#[1429](https://github.com/nix-rust/nix/pull/1429)) -- `AioCb` is now always pinned. Once a `libc::aiocb` gets sent to the kernel, - its address in memory must not change. Nix now enforces that by using - `std::pin`. Most users won't need to change anything, except when using - `aio_suspend`. See that method's documentation for the new usage. - (#[1440](https://github.com/nix-rust/nix/pull/1440)) -- `LioCb` is now constructed using a distinct `LioCbBuilder` struct. This - avoids a soundness issue with the old `LioCb`. Usage is similar but - construction now uses the builder pattern. See the documentation for - details. - (#[1440](https://github.com/nix-rust/nix/pull/1440)) -- Minimum supported Rust version is now 1.41.0. - ([#1440](https://github.com/nix-rust/nix/pull/1440)) -- Errno aliases are now associated consts on `Errno`, instead of consts in the - `errno` module. - (#[1452](https://github.com/nix-rust/nix/pull/1452)) - -### Fixed -- Allow `sockaddr_ll` size, as reported by the Linux kernel, to be smaller then it's definition - (#[1395](https://github.com/nix-rust/nix/pull/1395)) -- Fix spurious errors using `sendmmsg` with multiple cmsgs - (#[1414](https://github.com/nix-rust/nix/pull/1414)) -- Added `Errno::EOPNOTSUPP` to FreeBSD, where it was missing. - (#[1452](https://github.com/nix-rust/nix/pull/1452)) - -### Removed - -- Removed `sys::socket::accept4` from Android arm because libc removed it in - version 0.2.87. - ([#1399](https://github.com/nix-rust/nix/pull/1399)) -- `AioCb::from_boxed_slice` and `AioCb::from_boxed_mut_slice` have been - removed. They were useful with earlier versions of Rust, but should no - longer be needed now that async/await are available. `AioCb`s now work - exclusively with borrowed buffers, not owned ones. - (#[1440](https://github.com/nix-rust/nix/pull/1440)) -- Removed some Errno values from platforms where they aren't actually defined. - (#[1452](https://github.com/nix-rust/nix/pull/1452)) - -## [0.20.2] - 28 September 2021 -### Fixed -- Fixed buffer overflow in `unistd::getgrouplist`. - (#[1545](https://github.com/nix-rust/nix/pull/1545)) - -## [0.20.1] - 13 August 2021 -### Fixed -- Locked bitflags to < 1.3.0 to fix the build with rust < 1.46.0. - -### Removed -- Removed a couple of termios constants on redox that were never actually - supported. - (#[1483](https://github.com/nix-rust/nix/pull/1483)) - -## [0.20.0] - 20 February 2021 -### Added - -- Added a `passwd` field to `Group` (#[1338](https://github.com/nix-rust/nix/pull/1338)) -- Added `mremap` (#[1306](https://github.com/nix-rust/nix/pull/1306)) -- Added `personality` (#[1331](https://github.com/nix-rust/nix/pull/1331)) -- Added limited Fuchsia support (#[1285](https://github.com/nix-rust/nix/pull/1285)) -- Added `getpeereid` (#[1342](https://github.com/nix-rust/nix/pull/1342)) -- Implemented `IntoIterator` for `Dir` - (#[1333](https://github.com/nix-rust/nix/pull/1333)). - -### Changed - -- Minimum supported Rust version is now 1.40.0. - ([#1356](https://github.com/nix-rust/nix/pull/1356)) -- i686-apple-darwin has been demoted to Tier 2 support, because it's deprecated - by Xcode. - (#[1350](https://github.com/nix-rust/nix/pull/1350)) -- Fixed calling `recvfrom` on an `AddrFamily::Packet` socket - (#[1344](https://github.com/nix-rust/nix/pull/1344)) - -### Fixed -- `TimerFd` now closes the underlying fd on drop. - ([#1381](https://github.com/nix-rust/nix/pull/1381)) -- Define `*_MAGIC` filesystem constants on Linux s390x - (#[1372](https://github.com/nix-rust/nix/pull/1372)) -- mqueue, sysinfo, timespec, statfs, test_ptrace_syscall() on x32 - (#[1366](https://github.com/nix-rust/nix/pull/1366)) - -### Removed - -- `Dir`, `SignalFd`, and `PtyMaster` are no longer `Clone`. - (#[1382](https://github.com/nix-rust/nix/pull/1382)) -- Removed `SockLevel`, which hasn't been used for a few years - (#[1362](https://github.com/nix-rust/nix/pull/1362)) -- Removed both `Copy` and `Clone` from `TimerFd`. - ([#1381](https://github.com/nix-rust/nix/pull/1381)) - -## [0.19.1] - 28 November 2020 -### Fixed -- Fixed bugs in `recvmmsg`. - (#[1341](https://github.com/nix-rust/nix/pull/1341)) - -## [0.19.0] - 6 October 2020 -### Added -- Added Netlink protocol families to the `SockProtocol` enum - (#[1289](https://github.com/nix-rust/nix/pull/1289)) -- Added `clock_gettime`, `clock_settime`, `clock_getres`, - `clock_getcpuclockid` functions and `ClockId` struct. - (#[1281](https://github.com/nix-rust/nix/pull/1281)) -- Added wrapper functions for `PTRACE_SYSEMU` and `PTRACE_SYSEMU_SINGLESTEP`. - (#[1300](https://github.com/nix-rust/nix/pull/1300)) -- Add support for Vsock on Android rather than just Linux. - (#[1301](https://github.com/nix-rust/nix/pull/1301)) -- Added `TCP_KEEPCNT` and `TCP_KEEPINTVL` TCP keepalive options. - (#[1283](https://github.com/nix-rust/nix/pull/1283)) -### Changed -- Expose `SeekData` and `SeekHole` on all Linux targets - (#[1284](https://github.com/nix-rust/nix/pull/1284)) -- Changed unistd::{execv,execve,execvp,execvpe,fexecve,execveat} to take both `&[&CStr]` and `&[CString]` as its list argument(s). - (#[1278](https://github.com/nix-rust/nix/pull/1278)) -- Made `unistd::fork` an unsafe funtion, bringing it in line with [libstd's decision](https://github.com/rust-lang/rust/pull/58059). - (#[1293](https://github.com/nix-rust/nix/pull/1293)) - -## [0.18.0] - 26 July 2020 -### Added -- Added `fchown(2)` wrapper. - (#[1257](https://github.com/nix-rust/nix/pull/1257)) -- Added support on linux systems for `MAP_HUGE_`_`SIZE`_ family of flags. - (#[1211](https://github.com/nix-rust/nix/pull/1211)) -- Added support for `F_OFD_*` `fcntl` commands on Linux and Android. - (#[1195](https://github.com/nix-rust/nix/pull/1195)) -- Added `env::clearenv()`: calls `libc::clearenv` on platforms - where it's available, and clears the environment of all variables - via `std::env::vars` and `std::env::remove_var` on others. - (#[1185](https://github.com/nix-rust/nix/pull/1185)) -- `FsType` inner value made public. - (#[1187](https://github.com/nix-rust/nix/pull/1187)) -- Added `unistd::setfsuid` and `unistd::setfsgid` to set the user or group - identity for filesystem checks per-thread. - (#[1163](https://github.com/nix-rust/nix/pull/1163)) -- Derived `Ord`, `PartialOrd` for `unistd::Pid` (#[1189](https://github.com/nix-rust/nix/pull/1189)) -- Added `select::FdSet::fds` method to iterate over file descriptors in a set. - ([#1207](https://github.com/nix-rust/nix/pull/1207)) -- Added support for UDP generic segmentation offload (GSO) and generic - receive offload (GRO) ([#1209](https://github.com/nix-rust/nix/pull/1209)) -- Added support for `sendmmsg` and `recvmmsg` calls - (#[1208](https://github.com/nix-rust/nix/pull/1208)) -- Added support for `SCM_CREDS` messages (`UnixCredentials`) on FreeBSD/DragonFly - (#[1216](https://github.com/nix-rust/nix/pull/1216)) -- Added `BindToDevice` socket option (sockopt) on Linux - (#[1233](https://github.com/nix-rust/nix/pull/1233)) -- Added `EventFilter` bitflags for `EV_DISPATCH` and `EV_RECEIPT` on OpenBSD. - (#[1252](https://github.com/nix-rust/nix/pull/1252)) -- Added support for `Ipv4PacketInfo` and `Ipv6PacketInfo` to `ControlMessage`. - (#[1222](https://github.com/nix-rust/nix/pull/1222)) -- `CpuSet` and `UnixCredentials` now implement `Default`. - (#[1244](https://github.com/nix-rust/nix/pull/1244)) -- Added `unistd::ttyname` - (#[1259](https://github.com/nix-rust/nix/pull/1259)) -- Added support for `Ipv4PacketInfo` and `Ipv6PacketInfo` to `ControlMessage` for iOS and Android. - (#[1265](https://github.com/nix-rust/nix/pull/1265)) -- Added support for `TimerFd`. - (#[1261](https://github.com/nix-rust/nix/pull/1261)) - -### Changed -- Changed `fallocate` return type from `c_int` to `()` (#[1201](https://github.com/nix-rust/nix/pull/1201)) -- Enabled `sys::ptrace::setregs` and `sys::ptrace::getregs` on x86_64-unknown-linux-musl target - (#[1198](https://github.com/nix-rust/nix/pull/1198)) -- On Linux, `ptrace::write` is now an `unsafe` function. Caveat programmer. - (#[1245](https://github.com/nix-rust/nix/pull/1245)) -- `execv`, `execve`, `execvp` and `execveat` in `::nix::unistd` and `reboot` in - `::nix::sys::reboot` now return `Result<Infallible>` instead of `Result<Void>` (#[1239](https://github.com/nix-rust/nix/pull/1239)) -- `sys::socket::sockaddr_storage_to_addr` is no longer `unsafe`. So is - `offset_of!`. -- `sys::socket::sockaddr_storage_to_addr`, `offset_of!`, and `Errno::clear` are - no longer `unsafe`. -- `SockAddr::as_ffi_pair`,`sys::socket::sockaddr_storage_to_addr`, `offset_of!`, - and `Errno::clear` are no longer `unsafe`. - (#[1244](https://github.com/nix-rust/nix/pull/1244)) -- Several `Inotify` methods now take `self` by value instead of by reference - (#[1244](https://github.com/nix-rust/nix/pull/1244)) -- `nix::poll::ppoll`: `timeout` parameter is now optional, None is equivalent for infinite timeout. - -### Fixed - -- Fixed `getsockopt`. The old code produced UB which triggers a panic with - Rust 1.44.0. - (#[1214](https://github.com/nix-rust/nix/pull/1214)) - -- Fixed a bug in nix::unistd that would result in an infinite loop - when a group or user lookup required a buffer larger than - 16KB. (#[1198](https://github.com/nix-rust/nix/pull/1198)) -- Fixed unaligned casting of `cmsg_data` to `af_alg_iv` (#[1206](https://github.com/nix-rust/nix/pull/1206)) -- Fixed `readlink`/`readlinkat` when reading symlinks longer than `PATH_MAX` (#[1231](https://github.com/nix-rust/nix/pull/1231)) -- `PollFd`, `EpollEvent`, `IpMembershipRequest`, `Ipv6MembershipRequest`, - `TimeVal`, and `IoVec` are now `repr(transparent)`. This is required for - correctness's sake across all architectures and compilers, though now bugs - have been reported so far. - (#[1243](https://github.com/nix-rust/nix/pull/1243)) -- Fixed unaligned pointer read in `Inotify::read_events`. - (#[1244](https://github.com/nix-rust/nix/pull/1244)) - -### Removed - -- Removed `sys::socket::addr::from_libc_sockaddr` from the public API. - (#[1215](https://github.com/nix-rust/nix/pull/1215)) -- Removed `sys::termios::{get_libc_termios, get_libc_termios_mut, update_wrapper` - from the public API. These were previously hidden in the docs but still usable - by downstream. - (#[1235](https://github.com/nix-rust/nix/pull/1235)) - -- Nix no longer implements `NixPath` for `Option<P> where P: NixPath`. Most - Nix functions that accept `NixPath` arguments can't do anything useful with - `None`. The exceptions (`mount` and `quotactl_sync`) already take explicitly - optional arguments. - (#[1242](https://github.com/nix-rust/nix/pull/1242)) - -- Removed `unistd::daemon` and `unistd::pipe2` on OSX and ios - (#[1255](https://github.com/nix-rust/nix/pull/1255)) - -- Removed `sys::event::FilterFlag::NOTE_EXIT_REPARENTED` and - `sys::event::FilterFlag::NOTE_REAP` on OSX and ios. - (#[1255](https://github.com/nix-rust/nix/pull/1255)) - -- Removed `sys::ptrace::ptrace` on Android and Linux. - (#[1255](https://github.com/nix-rust/nix/pull/1255)) - -- Dropped support for powerpc64-unknown-linux-gnu - (#[1266](https://github.com/nix-rust/nix/pull/1268)) - -## [0.17.0] - 3 February 2020 -### Added -- Add `CLK_TCK` to `SysconfVar` - (#[1177](https://github.com/nix-rust/nix/pull/1177)) -### Removed -- Removed deprecated Error::description from error types - (#[1175](https://github.com/nix-rust/nix/pull/1175)) - -## [0.16.1] - 23 December 2019 -### Fixed - -- Fixed the build for OpenBSD - (#[1168](https://github.com/nix-rust/nix/pull/1168)) - -## [0.16.0] - 1 December 2019 -### Added -- Added `ptrace::seize()`: similar to `attach()` on Linux - but with better-defined semantics. - (#[1154](https://github.com/nix-rust/nix/pull/1154)) - -- Added `Signal::as_str()`: returns signal name as `&'static str` - (#[1138](https://github.com/nix-rust/nix/pull/1138)) - -- Added `posix_fallocate`. - ([#1105](https://github.com/nix-rust/nix/pull/1105)) - -- Implemented `Default` for `FdSet` - ([#1107](https://github.com/nix-rust/nix/pull/1107)) - -- Added `NixPath::is_empty`. - ([#1107](https://github.com/nix-rust/nix/pull/1107)) - -- Added `mkfifoat` - ([#1133](https://github.com/nix-rust/nix/pull/1133)) - -- Added `User::from_uid`, `User::from_name`, `User::from_gid` and - `Group::from_name`, - ([#1139](https://github.com/nix-rust/nix/pull/1139)) - -- Added `linkat` - ([#1101](https://github.com/nix-rust/nix/pull/1101)) - -- Added `sched_getaffinity`. - ([#1148](https://github.com/nix-rust/nix/pull/1148)) - -- Added optional `Signal` argument to `ptrace::{detach, syscall}` for signal - injection. ([#1083](https://github.com/nix-rust/nix/pull/1083)) - -### Changed -- `sys::termios::BaudRate` now implements `TryFrom<speed_t>` instead of - `From<speed_t>`. The old `From` implementation would panic on failure. - ([#1159](https://github.com/nix-rust/nix/pull/1159)) - -- `sys::socket::ControlMessage::ScmCredentials` and - `sys::socket::ControlMessageOwned::ScmCredentials` now wrap `UnixCredentials` - rather than `libc::ucred`. - ([#1160](https://github.com/nix-rust/nix/pull/1160)) - -- `sys::socket::recvmsg` now takes a plain `Vec` instead of a `CmsgBuffer` - implementor. If you were already using `cmsg_space!`, then you needn't worry. - ([#1156](https://github.com/nix-rust/nix/pull/1156)) - -- `sys::socket::recvfrom` now returns - `Result<(usize, Option<SockAddr>)>` instead of `Result<(usize, SockAddr)>`. - ([#1145](https://github.com/nix-rust/nix/pull/1145)) - -- `Signal::from_c_int` has been replaced by `Signal::try_from` - ([#1113](https://github.com/nix-rust/nix/pull/1113)) - -- Changed `readlink` and `readlinkat` to return `OsString` - ([#1109](https://github.com/nix-rust/nix/pull/1109)) - - ```rust - # use nix::fcntl::{readlink, readlinkat}; - // the buffer argument of `readlink` and `readlinkat` has been removed, - // and the return value is now an owned type (`OsString`). - // Existing code can be updated by removing the buffer argument - // and removing any clone or similar operation on the output - - // old code `readlink(&path, &mut buf)` can be replaced with the following - let _: OsString = readlink(&path); - - // old code `readlinkat(dirfd, &path, &mut buf)` can be replaced with the following - let _: OsString = readlinkat(dirfd, &path); - ``` - -- Minimum supported Rust version is now 1.36.0. - ([#1108](https://github.com/nix-rust/nix/pull/1108)) - -- `Ipv4Addr::octets`, `Ipv4Addr::to_std`, `Error::as_errno`, - `ForkResult::is_child`, `ForkResult::is_parent`, `Gid::as_raw`, - `Uid::is_root`, `Uid::as_raw`, `Pid::as_raw`, and `PollFd::revents` now take - `self` by value. - ([#1107](https://github.com/nix-rust/nix/pull/1107)) - -- Type `&CString` for parameters of `exec(v|ve|vp|vpe|veat)` are changed to `&CStr`. - ([#1121](https://github.com/nix-rust/nix/pull/1121)) - -### Fixed -- Fix length of abstract socket addresses - ([#1120](https://github.com/nix-rust/nix/pull/1120)) - -- Fix initialization of msghdr in recvmsg/sendmsg when built with musl - ([#1136](https://github.com/nix-rust/nix/pull/1136)) - -### Removed -- Remove the deprecated `CmsgSpace`. - ([#1156](https://github.com/nix-rust/nix/pull/1156)) - -## [0.15.0] - 10 August 2019 -### Added -- Added `MSG_WAITALL` to `MsgFlags` in `sys::socket`. - ([#1079](https://github.com/nix-rust/nix/pull/1079)) -- Implemented `Clone`, `Copy`, `Debug`, `Eq`, `Hash`, and `PartialEq` for most - types that support them. ([#1035](https://github.com/nix-rust/nix/pull/1035)) -- Added `copy_file_range` wrapper - ([#1069](https://github.com/nix-rust/nix/pull/1069)) -- Add `mkdirat`. - ([#1084](https://github.com/nix-rust/nix/pull/1084)) -- Add `posix_fadvise`. - ([#1089](https://github.com/nix-rust/nix/pull/1089)) -- Added `AF_VSOCK` to `AddressFamily`. - ([#1091](https://github.com/nix-rust/nix/pull/1091)) -- Add `unlinkat` - ([#1058](https://github.com/nix-rust/nix/pull/1058)) -- Add `renameat`. - ([#1097](https://github.com/nix-rust/nix/pull/1097)) - -### Changed -- Support for `ifaddrs` now present when building for Android. - ([#1077](https://github.com/nix-rust/nix/pull/1077)) -- Minimum supported Rust version is now 1.31.0 - ([#1035](https://github.com/nix-rust/nix/pull/1035)) - ([#1095](https://github.com/nix-rust/nix/pull/1095)) -- Now functions `statfs()` and `fstatfs()` return result with `Statfs` wrapper - ([#928](https://github.com/nix-rust/nix/pull/928)) - -### Fixed -- Enabled `sched_yield` for all nix hosts. - ([#1090](https://github.com/nix-rust/nix/pull/1090)) - -## [0.14.1] - 2019-06-06 -### Added -- Macros exported by `nix` may now be imported via `use` on the Rust 2018 - edition without importing helper macros on Linux targets. - ([#1066](https://github.com/nix-rust/nix/pull/1066)) - - For example, in Rust 2018, the `ioctl_read_bad!` macro can now be imported - without importing the `convert_ioctl_res!` macro. - - ```rust - use nix::ioctl_read_bad; - - ioctl_read_bad!(tcgets, libc::TCGETS, libc::termios); - ``` - -### Changed -- Changed some public types from reexports of libc types like `uint32_t` to the - native equivalents like `u32.` - ([#1072](https://github.com/nix-rust/nix/pull/1072/commits)) - -### Fixed -- Fix the build on Android and Linux/mips with recent versions of libc. - ([#1072](https://github.com/nix-rust/nix/pull/1072/commits)) - -## [0.14.0] - 2019-05-21 -### Added -- Add IP_RECVIF & IP_RECVDSTADDR. Enable IP_PKTINFO and IP6_PKTINFO on netbsd/openbsd. - ([#1002](https://github.com/nix-rust/nix/pull/1002)) -- Added `inotify_init1`, `inotify_add_watch` and `inotify_rm_watch` wrappers for - Android and Linux. ([#1016](https://github.com/nix-rust/nix/pull/1016)) -- Add `ALG_SET_IV`, `ALG_SET_OP` and `ALG_SET_AEAD_ASSOCLEN` control messages and `AF_ALG` - socket types on Linux and Android ([#1031](https://github.com/nix-rust/nix/pull/1031)) -- Add killpg - ([#1034](https://github.com/nix-rust/nix/pull/1034)) -- Added ENOTSUP errno support for Linux and Android. - ([#969](https://github.com/nix-rust/nix/pull/969)) -- Add several errno constants from OpenBSD 6.2 - ([#1036](https://github.com/nix-rust/nix/pull/1036)) -- Added `from_std` and `to_std` methods for `sys::socket::IpAddr` - ([#1043](https://github.com/nix-rust/nix/pull/1043)) -- Added `nix::unistd:seteuid` and `nix::unistd::setegid` for those platforms that do - not support `setresuid` nor `setresgid` respectively. - ([#1044](https://github.com/nix-rust/nix/pull/1044)) -- Added a `access` wrapper - ([#1045](https://github.com/nix-rust/nix/pull/1045)) -- Add `forkpty` - ([#1042](https://github.com/nix-rust/nix/pull/1042)) -- Add `sched_yield` - ([#1050](https://github.com/nix-rust/nix/pull/1050)) - -### Changed -- `PollFd` event flags renamed to `PollFlags` ([#1024](https://github.com/nix-rust/nix/pull/1024/)) -- `recvmsg` now returns an Iterator over `ControlMessageOwned` objects rather - than `ControlMessage` objects. This is sadly not backwards-compatible. Fix - code like this: - ```rust - if let ControlMessage::ScmRights(&fds) = cmsg { - ``` - - By replacing it with code like this: - ```rust - if let ControlMessageOwned::ScmRights(fds) = cmsg { - ``` - ([#1020](https://github.com/nix-rust/nix/pull/1020)) -- Replaced `CmsgSpace` with the `cmsg_space` macro. - ([#1020](https://github.com/nix-rust/nix/pull/1020)) - -### Fixed -- Fixed multiple bugs when using `sendmsg` and `recvmsg` with ancillary control messages - ([#1020](https://github.com/nix-rust/nix/pull/1020)) -- Macros exported by `nix` may now be imported via `use` on the Rust 2018 - edition without importing helper macros for BSD targets. - ([#1041](https://github.com/nix-rust/nix/pull/1041)) - - For example, in Rust 2018, the `ioctl_read_bad!` macro can now be imported - without importing the `convert_ioctl_res!` macro. - - ```rust - use nix::ioctl_read_bad; - - ioctl_read_bad!(tcgets, libc::TCGETS, libc::termios); - ``` - -### Removed -- `Daemon`, `NOTE_REAP`, and `NOTE_EXIT_REPARENTED` are now deprecated on OSX - and iOS. - ([#1033](https://github.com/nix-rust/nix/pull/1033)) -- `PTRACE_GETREGS`, `PTRACE_SETREGS`, `PTRACE_GETFPREGS`, and - `PTRACE_SETFPREGS` have been removed from some platforms where they never - should've been defined in the first place. - ([#1055](https://github.com/nix-rust/nix/pull/1055)) - -## [0.13.1] - 2019-06-10 -### Changed -- Changed some public types from reexports of libc types like `uint32_t` to the - native equivalents like `u32.` - ([#1072](https://github.com/nix-rust/nix/pull/1072/commits)) - -### Fixed -- Fix the build on Android and Linux/mips with recent versions of libc. - ([#1072](https://github.com/nix-rust/nix/pull/1072/commits)) -- Fixed build on Linux/arm and Linux/s390x with the latest Rust libc - ([52102cb](https://github.com/nix-rust/nix/commit/52102cb76398c4dfb9ea141b98c5b01a2e050973)) - -### Removed -- `Daemon`, `NOTE_REAP`, and `NOTE_EXIT_REPARENTED` are now deprecated on OSX - and iOS. - ([#1033](https://github.com/nix-rust/nix/pull/1033)) - -## [0.13.0] - 2019-01-15 -### Added -- Added PKTINFO(V4) & V6PKTINFO cmsg support - Android/FreeBSD/iOS/Linux/MacOS. - ([#990](https://github.com/nix-rust/nix/pull/990)) -- Added support of CString type in `setsockopt`. - ([#972](https://github.com/nix-rust/nix/pull/972)) -- Added option `TCP_CONGESTION` in `setsockopt`. - ([#972](https://github.com/nix-rust/nix/pull/972)) -- Added `symlinkat` wrapper. - ([#997](https://github.com/nix-rust/nix/pull/997)) -- Added `ptrace::{getregs, setregs}`. - ([#1010](https://github.com/nix-rust/nix/pull/1010)) -- Added `nix::sys::signal::signal`. - ([#817](https://github.com/nix-rust/nix/pull/817)) -- Added an `mprotect` wrapper. - ([#991](https://github.com/nix-rust/nix/pull/991)) - -### Fixed -- `lutimes` never worked on OpenBSD as it is not implemented on OpenBSD. It has - been removed. ([#1000](https://github.com/nix-rust/nix/pull/1000)) -- `fexecve` never worked on NetBSD or on OpenBSD as it is not implemented on - either OS. It has been removed. ([#1000](https://github.com/nix-rust/nix/pull/1000)) - -## [0.12.1] 2019-06-08 -### Changed -- Changed some public types from reexports of libc types like `uint32_t` to the - native equivalents like `u32.` - ([#1072](https://github.com/nix-rust/nix/pull/1072/commits)) - -### Fixed -- Fix the build on Android and Linux/mips with recent versions of libc. - ([#1072](https://github.com/nix-rust/nix/pull/1072/commits)) -- Fixed build on Linux/arm and Linux/s390x with the latest Rust libc - ([52102cb](https://github.com/nix-rust/nix/commit/52102cb76398c4dfb9ea141b98c5b01a2e050973)) - -### Removed -- `fexecve` never worked on NetBSD or on OpenBSD as it is not implemented on - either OS. It has been removed. ([#1000](https://github.com/nix-rust/nix/pull/1000)) -- `Daemon`, `NOTE_REAP`, and `NOTE_EXIT_REPARENTED` are now deprecated on OSX - and iOS. - ([#1033](https://github.com/nix-rust/nix/pull/1033)) - -## [0.12.0] 2018-11-28 - -### Added -- Added `FromStr` and `Display` impls for `nix::sys::Signal` - ([#884](https://github.com/nix-rust/nix/pull/884)) -- Added a `sync` wrapper. - ([#961](https://github.com/nix-rust/nix/pull/961)) -- Added a `sysinfo` wrapper. - ([#922](https://github.com/nix-rust/nix/pull/922)) -- Support the `SO_PEERCRED` socket option and the `UnixCredentials` type on all Linux and Android targets. - ([#921](https://github.com/nix-rust/nix/pull/921)) -- Added support for `SCM_CREDENTIALS`, allowing to send process credentials over Unix sockets. - ([#923](https://github.com/nix-rust/nix/pull/923)) -- Added a `dir` module for reading directories (wraps `fdopendir`, `readdir`, and `rewinddir`). - ([#916](https://github.com/nix-rust/nix/pull/916)) -- Added `kmod` module that allows loading and unloading kernel modules on Linux. - ([#930](https://github.com/nix-rust/nix/pull/930)) -- Added `futimens` and `utimesat` wrappers ([#944](https://github.com/nix-rust/nix/pull/944)), - an `lutimes` wrapper ([#967](https://github.com/nix-rust/nix/pull/967)), - and a `utimes` wrapper ([#946](https://github.com/nix-rust/nix/pull/946)). -- Added `AF_UNSPEC` wrapper to `AddressFamily` ([#948](https://github.com/nix-rust/nix/pull/948)) -- Added the `mode_t` public alias within `sys::stat`. - ([#954](https://github.com/nix-rust/nix/pull/954)) -- Added a `truncate` wrapper. - ([#956](https://github.com/nix-rust/nix/pull/956)) -- Added a `fchownat` wrapper. - ([#955](https://github.com/nix-rust/nix/pull/955)) -- Added support for `ptrace` on BSD operating systems ([#949](https://github.com/nix-rust/nix/pull/949)) -- Added `ptrace` functions for reads and writes to tracee memory and ptrace kill - ([#949](https://github.com/nix-rust/nix/pull/949)) ([#958](https://github.com/nix-rust/nix/pull/958)) -- Added a `acct` wrapper module for enabling and disabling process accounting - ([#952](https://github.com/nix-rust/nix/pull/952)) -- Added the `time_t` and `suseconds_t` public aliases within `sys::time`. - ([#968](https://github.com/nix-rust/nix/pull/968)) -- Added `unistd::execvpe` for Haiku, Linux and OpenBSD - ([#975](https://github.com/nix-rust/nix/pull/975)) -- Added `Error::as_errno`. - ([#977](https://github.com/nix-rust/nix/pull/977)) - -### Changed -- Increased required Rust version to 1.24.1 - ([#900](https://github.com/nix-rust/nix/pull/900)) - ([#966](https://github.com/nix-rust/nix/pull/966)) - -### Fixed -- Made `preadv` take immutable slice of IoVec. - ([#914](https://github.com/nix-rust/nix/pull/914)) -- Fixed passing multiple file descriptors over Unix Sockets. - ([#918](https://github.com/nix-rust/nix/pull/918)) - -## [0.11.1] 2019-06-06 -### Changed -- Changed some public types from reexports of libc types like `uint32_t` to the - native equivalents like `u32.` - ([#1072](https://github.com/nix-rust/nix/pull/1072/commits)) - -### Fixed -- Fix the build on Android and Linux/mips with recent versions of libc. - ([#1072](https://github.com/nix-rust/nix/pull/1072/commits)) -- Fixed build on Linux/arm and Linux/s390x with the latest Rust libc - ([52102cb](https://github.com/nix-rust/nix/commit/52102cb76398c4dfb9ea141b98c5b01a2e050973)) - -### Removed -- `fexecve` never worked on NetBSD or on OpenBSD as it is not implemented on - either OS. It has been removed. ([#1000](https://github.com/nix-rust/nix/pull/1000)) -- `Daemon`, `NOTE_REAP`, and `NOTE_EXIT_REPARENTED` are now deprecated on OSX - and iOS. - ([#1033](https://github.com/nix-rust/nix/pull/1033)) - -## [0.11.0] 2018-06-01 - -### Added -- Added `sendfile` on FreeBSD and Darwin. - ([#901](https://github.com/nix-rust/nix/pull/901)) -- Added `pselect` - ([#894](https://github.com/nix-rust/nix/pull/894)) -- Exposed `preadv` and `pwritev` on the BSDs. - ([#883](https://github.com/nix-rust/nix/pull/883)) -- Added `mlockall` and `munlockall` - ([#876](https://github.com/nix-rust/nix/pull/876)) -- Added `SO_MARK` on Linux. - ([#873](https://github.com/nix-rust/nix/pull/873)) -- Added safe support for nearly any buffer type in the `sys::aio` module. - ([#872](https://github.com/nix-rust/nix/pull/872)) -- Added `sys::aio::LioCb` as a wrapper for `libc::lio_listio`. - ([#872](https://github.com/nix-rust/nix/pull/872)) -- Added `unistd::getsid` - ([#850](https://github.com/nix-rust/nix/pull/850)) -- Added `alarm`. ([#830](https://github.com/nix-rust/nix/pull/830)) -- Added interface flags `IFF_NO_PI, IFF_TUN, IFF_TAP` on linux-like systems. - ([#853](https://github.com/nix-rust/nix/pull/853)) -- Added `statvfs` module to all MacOS and Linux architectures. - ([#832](https://github.com/nix-rust/nix/pull/832)) -- Added `EVFILT_EMPTY`, `EVFILT_PROCDESC`, and `EVFILT_SENDFILE` on FreeBSD. - ([#825](https://github.com/nix-rust/nix/pull/825)) -- Exposed `termios::cfmakesane` on FreeBSD. - ([#825](https://github.com/nix-rust/nix/pull/825)) -- Exposed `MSG_CMSG_CLOEXEC` on *BSD. - ([#825](https://github.com/nix-rust/nix/pull/825)) -- Added `fchmod`, `fchmodat`. - ([#857](https://github.com/nix-rust/nix/pull/857)) -- Added `request_code_write_int!` on FreeBSD/DragonFlyBSD - ([#833](https://github.com/nix-rust/nix/pull/833)) - -### Changed -- `Display` and `Debug` for `SysControlAddr` now includes all fields. - ([#837](https://github.com/nix-rust/nix/pull/837)) -- `ioctl!` has been replaced with a family of `ioctl_*!` macros. - ([#833](https://github.com/nix-rust/nix/pull/833)) -- `io!`, `ior!`, `iow!`, and `iorw!` has been renamed to `request_code_none!`, `request_code_read!`, - `request_code_write!`, and `request_code_readwrite!` respectively. These have also now been exposed - in the documentation. - ([#833](https://github.com/nix-rust/nix/pull/833)) -- Enabled more `ptrace::Request` definitions for uncommon Linux platforms - ([#892](https://github.com/nix-rust/nix/pull/892)) -- Emulation of `FD_CLOEXEC` and `O_NONBLOCK` was removed from `socket()`, `accept4()`, and - `socketpair()`. - ([#907](https://github.com/nix-rust/nix/pull/907)) - -### Fixed -- Fixed possible panics when using `SigAction::flags` on Linux - ([#869](https://github.com/nix-rust/nix/pull/869)) -- Properly exposed 460800 and 921600 baud rates on NetBSD - ([#837](https://github.com/nix-rust/nix/pull/837)) -- Fixed `ioctl_write_int!` on FreeBSD/DragonFlyBSD - ([#833](https://github.com/nix-rust/nix/pull/833)) -- `ioctl_write_int!` now properly supports passing a `c_ulong` as the parameter on Linux non-musl targets - ([#833](https://github.com/nix-rust/nix/pull/833)) - -### Removed -- Removed explicit support for the `bytes` crate from the `sys::aio` module. - See `sys::aio::AioCb::from_boxed_slice` examples for alternatives. - ([#872](https://github.com/nix-rust/nix/pull/872)) -- Removed `sys::aio::lio_listio`. Use `sys::aio::LioCb::listio` instead. - ([#872](https://github.com/nix-rust/nix/pull/872)) -- Removed emulated `accept4()` from macos, ios, and netbsd targets - ([#907](https://github.com/nix-rust/nix/pull/907)) -- Removed `IFF_NOTRAILERS` on OpenBSD, as it has been removed in OpenBSD 6.3 - ([#893](https://github.com/nix-rust/nix/pull/893)) - -## [0.10.0] 2018-01-26 - -### Added -- Added specialized wrapper: `sys::ptrace::step` - ([#852](https://github.com/nix-rust/nix/pull/852)) -- Added `AioCb::from_ptr` and `AioCb::from_mut_ptr` - ([#820](https://github.com/nix-rust/nix/pull/820)) -- Added specialized wrappers: `sys::ptrace::{traceme, syscall, cont, attach}`. Using the matching routines - with `sys::ptrace::ptrace` is now deprecated. -- Added `nix::poll` module for all platforms - ([#672](https://github.com/nix-rust/nix/pull/672)) -- Added `nix::ppoll` function for FreeBSD and DragonFly - ([#672](https://github.com/nix-rust/nix/pull/672)) -- Added protocol families in `AddressFamily` enum. - ([#647](https://github.com/nix-rust/nix/pull/647)) -- Added the `pid()` method to `WaitStatus` for extracting the PID. - ([#722](https://github.com/nix-rust/nix/pull/722)) -- Added `nix::unistd:fexecve`. - ([#727](https://github.com/nix-rust/nix/pull/727)) -- Expose `uname()` on all platforms. - ([#739](https://github.com/nix-rust/nix/pull/739)) -- Expose `signalfd` module on Android as well. - ([#739](https://github.com/nix-rust/nix/pull/739)) -- Added `nix::sys::ptrace::detach`. - ([#749](https://github.com/nix-rust/nix/pull/749)) -- Added timestamp socket control message variant: - `nix::sys::socket::ControlMessage::ScmTimestamp` - ([#663](https://github.com/nix-rust/nix/pull/663)) -- Added socket option variant that enables the timestamp socket - control message: `nix::sys::socket::sockopt::ReceiveTimestamp` - ([#663](https://github.com/nix-rust/nix/pull/663)) -- Added more accessor methods for `AioCb` - ([#773](https://github.com/nix-rust/nix/pull/773)) -- Add `nix::sys::fallocate` - ([#768](https:://github.com/nix-rust/nix/pull/768)) -- Added `nix::unistd::mkfifo`. - ([#602](https://github.com/nix-rust/nix/pull/774)) -- Added `ptrace::Options::PTRACE_O_EXITKILL` on Linux and Android. - ([#771](https://github.com/nix-rust/nix/pull/771)) -- Added `nix::sys::uio::{process_vm_readv, process_vm_writev}` on Linux - ([#568](https://github.com/nix-rust/nix/pull/568)) -- Added `nix::unistd::{getgroups, setgroups, getgrouplist, initgroups}`. ([#733](https://github.com/nix-rust/nix/pull/733)) -- Added `nix::sys::socket::UnixAddr::as_abstract` on Linux and Android. - ([#785](https://github.com/nix-rust/nix/pull/785)) -- Added `nix::unistd::execveat` on Linux and Android. - ([#800](https://github.com/nix-rust/nix/pull/800)) -- Added the `from_raw()` method to `WaitStatus` for converting raw status values - to `WaitStatus` independent of syscalls. - ([#741](https://github.com/nix-rust/nix/pull/741)) -- Added more standard trait implementations for various types. - ([#814](https://github.com/nix-rust/nix/pull/814)) -- Added `sigprocmask` to the signal module. - ([#826](https://github.com/nix-rust/nix/pull/826)) -- Added `nix::sys::socket::LinkAddr` on Linux and all bsdlike system. - ([#813](https://github.com/nix-rust/nix/pull/813)) -- Add socket options for `IP_TRANSPARENT` / `BIND_ANY`. - ([#835](https://github.com/nix-rust/nix/pull/835)) - -### Changed -- Exposed the `mqueue` module for all supported operating systems. - ([#834](https://github.com/nix-rust/nix/pull/834)) -- Use native `pipe2` on all BSD targets. Users should notice no difference. - ([#777](https://github.com/nix-rust/nix/pull/777)) -- Renamed existing `ptrace` wrappers to encourage namespacing ([#692](https://github.com/nix-rust/nix/pull/692)) -- Marked `sys::ptrace::ptrace` as `unsafe`. -- Changed function signature of `socket()` and `socketpair()`. The `protocol` argument - has changed type from `c_int` to `SockProtocol`. - It accepts a `None` value for default protocol that was specified with zero using `c_int`. - ([#647](https://github.com/nix-rust/nix/pull/647)) -- Made `select` easier to use, adding the ability to automatically calculate the `nfds` parameter using the new - `FdSet::highest` ([#701](https://github.com/nix-rust/nix/pull/701)) -- Exposed `unistd::setresuid` and `unistd::setresgid` on FreeBSD and OpenBSD - ([#721](https://github.com/nix-rust/nix/pull/721)) -- Refactored the `statvfs` module removing extraneous API functions and the - `statvfs::vfs` module. Additionally `(f)statvfs()` now return the struct - directly. And the returned `Statvfs` struct now exposes its data through - accessor methods. ([#729](https://github.com/nix-rust/nix/pull/729)) -- The `addr` argument to `madvise` and `msync` is now `*mut` to better match the - libc API. ([#731](https://github.com/nix-rust/nix/pull/731)) -- `shm_open` and `shm_unlink` are no longer exposed on Android targets, where - they are not officially supported. ([#731](https://github.com/nix-rust/nix/pull/731)) -- `MapFlags`, `MmapAdvise`, and `MsFlags` expose some more variants and only - officially-supported variants are provided for each target. - ([#731](https://github.com/nix-rust/nix/pull/731)) -- Marked `pty::ptsname` function as `unsafe` - ([#744](https://github.com/nix-rust/nix/pull/744)) -- Moved constants ptrace request, event and options to enums and updated ptrace functions and argument types accordingly. - ([#749](https://github.com/nix-rust/nix/pull/749)) -- `AioCb::Drop` will now panic if the `AioCb` is still in-progress ([#715](https://github.com/nix-rust/nix/pull/715)) -- Restricted `nix::sys::socket::UnixAddr::new_abstract` to Linux and Android only. - ([#785](https://github.com/nix-rust/nix/pull/785)) -- The `ucred` struct has been removed in favor of a `UserCredentials` struct that - contains only getters for its fields. - ([#814](https://github.com/nix-rust/nix/pull/814)) -- Both `ip_mreq` and `ipv6_mreq` have been replaced with `IpMembershipRequest` and - `Ipv6MembershipRequest`. - ([#814](https://github.com/nix-rust/nix/pull/814)) -- Removed return type from `pause`. - ([#829](https://github.com/nix-rust/nix/pull/829)) -- Changed the termios APIs to allow for using a `u32` instead of the `BaudRate` - enum on BSD platforms to support arbitrary baud rates. See the module docs for - `nix::sys::termios` for more details. - ([#843](https://github.com/nix-rust/nix/pull/843)) - -### Fixed -- Fix compilation and tests for OpenBSD targets - ([#688](https://github.com/nix-rust/nix/pull/688)) -- Fixed error handling in `AioCb::fsync`, `AioCb::read`, and `AioCb::write`. - It is no longer an error to drop an `AioCb` that failed to enqueue in the OS. - ([#715](https://github.com/nix-rust/nix/pull/715)) -- Fix potential memory corruption on non-Linux platforms when using - `sendmsg`/`recvmsg`, caused by mismatched `msghdr` definition. - ([#648](https://github.com/nix-rust/nix/pull/648)) - -### Removed -- `AioCb::from_boxed_slice` has been removed. It was never actually safe. Use - `from_bytes` or `from_bytes_mut` instead. - ([#820](https://github.com/nix-rust/nix/pull/820)) -- The syscall module has been removed. This only exposed enough functionality for - `memfd_create()` and `pivot_root()`, which are still exposed as separate functions. - ([#747](https://github.com/nix-rust/nix/pull/747)) -- The `Errno` variants are no longer reexported from the `errno` module. `Errno` itself is no longer reexported from the - crate root and instead must be accessed using the `errno` module. ([#696](https://github.com/nix-rust/nix/pull/696)) -- Removed `MS_VERBOSE`, `MS_NOSEC`, and `MS_BORN` from `MsFlags`. These - are internal kernel flags and should never have been exposed. - ([#814](https://github.com/nix-rust/nix/pull/814)) - - -## [0.9.0] 2017-07-23 - -### Added -- Added `sysconf`, `pathconf`, and `fpathconf` - ([#630](https://github.com/nix-rust/nix/pull/630) -- Added `sys::signal::SigAction::{ flags, mask, handler}` - ([#611](https://github.com/nix-rust/nix/pull/609) -- Added `nix::sys::pthread::pthread_self` - ([#591](https://github.com/nix-rust/nix/pull/591) -- Added `AioCb::from_boxed_slice` - ([#582](https://github.com/nix-rust/nix/pull/582) -- Added `nix::unistd::{openat, fstatat, readlink, readlinkat}` - ([#551](https://github.com/nix-rust/nix/pull/551)) -- Added `nix::pty::{grantpt, posix_openpt, ptsname/ptsname_r, unlockpt}` - ([#556](https://github.com/nix-rust/nix/pull/556) -- Added `nix::ptr::openpty` - ([#456](https://github.com/nix-rust/nix/pull/456)) -- Added `nix::ptrace::{ptrace_get_data, ptrace_getsiginfo, ptrace_setsiginfo - and nix::Error::UnsupportedOperation}` - ([#614](https://github.com/nix-rust/nix/pull/614)) -- Added `cfmakeraw`, `cfsetspeed`, and `tcgetsid`. ([#527](https://github.com/nix-rust/nix/pull/527)) -- Added "bad none", "bad write_ptr", "bad write_int", and "bad readwrite" variants to the `ioctl!` - macro. ([#670](https://github.com/nix-rust/nix/pull/670)) -- On Linux and Android, added support for receiving `PTRACE_O_TRACESYSGOOD` - events from `wait` and `waitpid` using `WaitStatus::PtraceSyscall` - ([#566](https://github.com/nix-rust/nix/pull/566)). - -### Changed -- The `ioctl!` macro and its variants now allow the generated functions to have - doccomments. ([#661](https://github.com/nix-rust/nix/pull/661)) -- Changed `ioctl!(write ...)` into `ioctl!(write_ptr ...)` and `ioctl!(write_int ..)` variants - to more clearly separate those use cases. ([#670](https://github.com/nix-rust/nix/pull/670)) -- Marked `sys::mman::{ mmap, munmap, madvise, munlock, msync }` as unsafe. - ([#559](https://github.com/nix-rust/nix/pull/559)) -- Minimum supported Rust version is now 1.13. -- Removed `revents` argument from `PollFd::new()` as it's an output argument and - will be overwritten regardless of value. - ([#542](https://github.com/nix-rust/nix/pull/542)) -- Changed type signature of `sys::select::FdSet::contains` to make `self` - immutable ([#564](https://github.com/nix-rust/nix/pull/564)) -- Introduced wrapper types for `gid_t`, `pid_t`, and `uid_t` as `Gid`, `Pid`, and `Uid` - respectively. Various functions have been changed to use these new types as - arguments. ([#629](https://github.com/nix-rust/nix/pull/629)) -- Fixed compilation on all Android and iOS targets ([#527](https://github.com/nix-rust/nix/pull/527)) - and promoted them to Tier 2 support. -- `nix::sys::statfs::{statfs,fstatfs}` uses statfs definition from `libc::statfs` instead of own linux specific type `nix::sys::Statfs`. - Also file system type constants like `nix::sys::statfs::ADFS_SUPER_MAGIC` were removed in favor of the libc equivalent. - ([#561](https://github.com/nix-rust/nix/pull/561)) -- Revised the termios API including additional tests and documentation and exposed it on iOS. ([#527](https://github.com/nix-rust/nix/pull/527)) -- `eventfd`, `signalfd`, and `pwritev`/`preadv` functionality is now included by default for all - supported platforms. ([#681](https://github.com/nix-rust/nix/pull/561)) -- The `ioctl!` macro's plain variants has been replaced with "bad read" to be consistent with - other variants. The generated functions also have more strict types for their arguments. The - "*_buf" variants also now calculate total array size and take slice references for improved type - safety. The documentation has also been dramatically improved. - ([#670](https://github.com/nix-rust/nix/pull/670)) - -### Removed -- Removed `io::Error` from `nix::Error` and the conversion from `nix::Error` to `Errno` - ([#614](https://github.com/nix-rust/nix/pull/614)) -- All feature flags have been removed in favor of conditional compilation on supported platforms. - `execvpe` is no longer supported, but this was already broken and will be added back in the next - release. ([#681](https://github.com/nix-rust/nix/pull/561)) -- Removed `ioc_*` functions and many helper constants and macros within the `ioctl` module. These - should always have been private and only the `ioctl!` should be used in public code. - ([#670](https://github.com/nix-rust/nix/pull/670)) - -### Fixed -- Fixed multiple issues compiling under different archetectures and OSes. - Now compiles on Linux/MIPS ([#538](https://github.com/nix-rust/nix/pull/538)), - `Linux/PPC` ([#553](https://github.com/nix-rust/nix/pull/553)), - `MacOS/x86_64,i686` ([#553](https://github.com/nix-rust/nix/pull/553)), - `NetBSD/x64_64` ([#538](https://github.com/nix-rust/nix/pull/538)), - `FreeBSD/x86_64,i686` ([#536](https://github.com/nix-rust/nix/pull/536)), and - `Android` ([#631](https://github.com/nix-rust/nix/pull/631)). -- `bind` and `errno_location` now work correctly on `Android` - ([#631](https://github.com/nix-rust/nix/pull/631)) -- Added `nix::ptrace` on all Linux-kernel-based platforms - [#624](https://github.com/nix-rust/nix/pull/624). Previously it was - only available on x86, x86-64, and ARM, and also not on Android. -- Fixed `sys::socket::sendmsg` with zero entry `cmsgs` parameter. - ([#623](https://github.com/nix-rust/nix/pull/623)) -- Multiple constants related to the termios API have now been properly defined for - all supported platforms. ([#527](https://github.com/nix-rust/nix/pull/527)) -- `ioctl!` macro now supports working with non-int datatypes and properly supports all platforms. - ([#670](https://github.com/nix-rust/nix/pull/670)) - -## [0.8.1] 2017-04-16 - -### Fixed -- Fixed build on FreeBSD. (Cherry-picked - [a859ee3c](https://github.com/nix-rust/nix/commit/a859ee3c9396dfdb118fcc2c8ecc697e2d303467)) - -## [0.8.0] 2017-03-02 - -### Added -- Added `::nix::sys::termios::BaudRate` enum to provide portable baudrate - values. ([#518](https://github.com/nix-rust/nix/pull/518)) -- Added a new `WaitStatus::PtraceEvent` to support ptrace events on Linux - and Android ([#438](https://github.com/nix-rust/nix/pull/438)) -- Added support for POSIX AIO - ([#483](https://github.com/nix-rust/nix/pull/483)) - ([#506](https://github.com/nix-rust/nix/pull/506)) -- Added support for XNU system control sockets - ([#478](https://github.com/nix-rust/nix/pull/478)) -- Added support for `ioctl` calls on BSD platforms - ([#478](https://github.com/nix-rust/nix/pull/478)) -- Added struct `TimeSpec` - ([#475](https://github.com/nix-rust/nix/pull/475)) - ([#483](https://github.com/nix-rust/nix/pull/483)) -- Added complete definitions for all kqueue-related constants on all supported - OSes - ([#415](https://github.com/nix-rust/nix/pull/415)) -- Added function `epoll_create1` and bitflags `EpollCreateFlags` in - `::nix::sys::epoll` in order to support `::libc::epoll_create1`. - ([#410](https://github.com/nix-rust/nix/pull/410)) -- Added `setresuid` and `setresgid` for Linux in `::nix::unistd` - ([#448](https://github.com/nix-rust/nix/pull/448)) -- Added `getpgid` in `::nix::unistd` - ([#433](https://github.com/nix-rust/nix/pull/433)) -- Added `tcgetpgrp` and `tcsetpgrp` in `::nix::unistd` - ([#451](https://github.com/nix-rust/nix/pull/451)) -- Added `CLONE_NEWCGROUP` in `::nix::sched` - ([#457](https://github.com/nix-rust/nix/pull/457)) -- Added `getpgrp` in `::nix::unistd` - ([#491](https://github.com/nix-rust/nix/pull/491)) -- Added `fchdir` in `::nix::unistd` - ([#497](https://github.com/nix-rust/nix/pull/497)) -- Added `major` and `minor` in `::nix::sys::stat` for decomposing `dev_t` - ([#508](https://github.com/nix-rust/nix/pull/508)) -- Fixed the style of many bitflags and use `libc` in more places. - ([#503](https://github.com/nix-rust/nix/pull/503)) -- Added `ppoll` in `::nix::poll` - ([#520](https://github.com/nix-rust/nix/pull/520)) -- Added support for getting and setting pipe size with fcntl(2) on Linux - ([#540](https://github.com/nix-rust/nix/pull/540)) - -### Changed -- `::nix::sys::termios::{cfgetispeed, cfsetispeed, cfgetospeed, cfsetospeed}` - switched to use `BaudRate` enum from `speed_t`. - ([#518](https://github.com/nix-rust/nix/pull/518)) -- `epoll_ctl` now could accept None as argument `event` - when op is `EpollOp::EpollCtlDel`. - ([#480](https://github.com/nix-rust/nix/pull/480)) -- Removed the `bad` keyword from the `ioctl!` macro - ([#478](https://github.com/nix-rust/nix/pull/478)) -- Changed `TimeVal` into an opaque Newtype - ([#475](https://github.com/nix-rust/nix/pull/475)) -- `kill`'s signature, defined in `::nix::sys::signal`, changed, so that the - signal parameter has type `T: Into<Option<Signal>>`. `None` as an argument - for that parameter will result in a 0 passed to libc's `kill`, while a - `Some`-argument will result in the previous behavior for the contained - `Signal`. - ([#445](https://github.com/nix-rust/nix/pull/445)) -- The minimum supported version of rustc is now 1.7.0. - ([#444](https://github.com/nix-rust/nix/pull/444)) -- Changed `KEvent` to an opaque structure that may only be modified by its - constructor and the `ev_set` method. - ([#415](https://github.com/nix-rust/nix/pull/415)) - ([#442](https://github.com/nix-rust/nix/pull/442)) - ([#463](https://github.com/nix-rust/nix/pull/463)) -- `pipe2` now calls `libc::pipe2` where available. Previously it was emulated - using `pipe`, which meant that setting `O_CLOEXEC` was not atomic. - ([#427](https://github.com/nix-rust/nix/pull/427)) -- Renamed `EpollEventKind` to `EpollFlags` in `::nix::sys::epoll` in order for - it to conform with our conventions. - ([#410](https://github.com/nix-rust/nix/pull/410)) -- `EpollEvent` in `::nix::sys::epoll` is now an opaque proxy for - `::libc::epoll_event`. The formerly public field `events` is now be read-only - accessible with the new method `events()` of `EpollEvent`. Instances of - `EpollEvent` can be constructed using the new method `new()` of EpollEvent. - ([#410](https://github.com/nix-rust/nix/pull/410)) -- `SigFlags` in `::nix::sys::signal` has be renamed to `SigmaskHow` and its type - has changed from `bitflags` to `enum` in order to conform to our conventions. - ([#460](https://github.com/nix-rust/nix/pull/460)) -- `sethostname` now takes a `&str` instead of a `&[u8]` as this provides an API - that makes more sense in normal, correct usage of the API. -- `gethostname` previously did not expose the actual length of the hostname - written from the underlying system call at all. This has been updated to - return a `&CStr` within the provided buffer that is always properly - NUL-terminated (this is not guaranteed by the call with all platforms/libc - implementations). -- Exposed all fcntl(2) operations at the module level, so they can be - imported direclty instead of via `FcntlArg` enum. - ([#541](https://github.com/nix-rust/nix/pull/541)) - -### Fixed -- Fixed multiple issues with Unix domain sockets on non-Linux OSes - ([#474](https://github.com/nix-rust/nix/pull/415)) -- Fixed using kqueue with `EVFILT_USER` on FreeBSD - ([#415](https://github.com/nix-rust/nix/pull/415)) -- Fixed the build on FreeBSD, and fixed the getsockopt, sendmsg, and recvmsg - functions on that same OS. - ([#397](https://github.com/nix-rust/nix/pull/397)) -- Fixed an off-by-one bug in `UnixAddr::new_abstract` in `::nix::sys::socket`. - ([#429](https://github.com/nix-rust/nix/pull/429)) -- Fixed clone passing a potentially unaligned stack. - ([#490](https://github.com/nix-rust/nix/pull/490)) -- Fixed mkdev not creating a `dev_t` the same way as libc. - ([#508](https://github.com/nix-rust/nix/pull/508)) - -## [0.7.0] 2016-09-09 - -### Added -- Added `lseek` and `lseek64` in `::nix::unistd` - ([#377](https://github.com/nix-rust/nix/pull/377)) -- Added `mkdir` and `getcwd` in `::nix::unistd` - ([#416](https://github.com/nix-rust/nix/pull/416)) -- Added accessors `sigmask_mut` and `sigmask` to `UContext` in - `::nix::ucontext`. - ([#370](https://github.com/nix-rust/nix/pull/370)) -- Added `WUNTRACED` to `WaitPidFlag` in `::nix::sys::wait` for non-_linux_ - targets. - ([#379](https://github.com/nix-rust/nix/pull/379)) -- Added new module `::nix::sys::reboot` with enumeration `RebootMode` and - functions `reboot` and `set_cad_enabled`. Currently for _linux_ only. - ([#386](https://github.com/nix-rust/nix/pull/386)) -- `FdSet` in `::nix::sys::select` now also implements `Clone`. - ([#405](https://github.com/nix-rust/nix/pull/405)) -- Added `F_FULLFSYNC` to `FcntlArg` in `::nix::fcntl` for _apple_ targets. - ([#407](https://github.com/nix-rust/nix/pull/407)) -- Added `CpuSet::unset` in `::nix::sched`. - ([#402](https://github.com/nix-rust/nix/pull/402)) -- Added constructor method `new()` to `PollFd` in `::nix::poll`, in order to - allow creation of objects, after removing public access to members. - ([#399](https://github.com/nix-rust/nix/pull/399)) -- Added method `revents()` to `PollFd` in `::nix::poll`, in order to provide - read access to formerly public member `revents`. - ([#399](https://github.com/nix-rust/nix/pull/399)) -- Added `MSG_CMSG_CLOEXEC` to `MsgFlags` in `::nix::sys::socket` for _linux_ only. - ([#422](https://github.com/nix-rust/nix/pull/422)) - -### Changed -- Replaced the reexported integer constants for signals by the enumeration - `Signal` in `::nix::sys::signal`. - ([#362](https://github.com/nix-rust/nix/pull/362)) -- Renamed `EventFdFlag` to `EfdFlags` in `::nix::sys::eventfd`. - ([#383](https://github.com/nix-rust/nix/pull/383)) -- Changed the result types of `CpuSet::is_set` and `CpuSet::set` in - `::nix::sched` to `Result<bool>` and `Result<()>`, respectively. They now - return `EINVAL`, if an invalid argument for the `field` parameter is passed. - ([#402](https://github.com/nix-rust/nix/pull/402)) -- `MqAttr` in `::nix::mqueue` is now an opaque proxy for `::libc::mq_attr`, - which has the same structure as the old `MqAttr`. The field `mq_flags` of - `::libc::mq_attr` is readable using the new method `flags()` of `MqAttr`. - `MqAttr` also no longer implements `Debug`. - ([#392](https://github.com/nix-rust/nix/pull/392)) -- The parameter `msq_prio` of `mq_receive` with type `u32` in `::nix::mqueue` - was replaced by a parameter named `msg_prio` with type `&mut u32`, so that - the message priority can be obtained by the caller. - ([#392](https://github.com/nix-rust/nix/pull/392)) -- The type alias `MQd` in `::nix::queue` was replaced by the type alias - `libc::mqd_t`, both of which are aliases for the same type. - ([#392](https://github.com/nix-rust/nix/pull/392)) - -### Removed -- Type alias `SigNum` from `::nix::sys::signal`. - ([#362](https://github.com/nix-rust/nix/pull/362)) -- Type alias `CpuMask` from `::nix::shed`. - ([#402](https://github.com/nix-rust/nix/pull/402)) -- Removed public fields from `PollFd` in `::nix::poll`. (See also added method - `revents()`. - ([#399](https://github.com/nix-rust/nix/pull/399)) - -### Fixed -- Fixed the build problem for NetBSD (Note, that we currently do not support - it, so it might already be broken again). - ([#389](https://github.com/nix-rust/nix/pull/389)) -- Fixed the build on FreeBSD, and fixed the getsockopt, sendmsg, and recvmsg - functions on that same OS. - ([#397](https://github.com/nix-rust/nix/pull/397)) - -## [0.6.0] 2016-06-10 - -### Added -- Added `gettid` in `::nix::unistd` for _linux_ and _android_. - ([#293](https://github.com/nix-rust/nix/pull/293)) -- Some _mips_ support in `::nix::sched` and `::nix::sys::syscall`. - ([#301](https://github.com/nix-rust/nix/pull/301)) -- Added `SIGNALFD_SIGINFO_SIZE` in `::nix::sys::signalfd`. - ([#309](https://github.com/nix-rust/nix/pull/309)) -- Added new module `::nix::ucontext` with struct `UContext`. Currently for - _linux_ only. - ([#311](https://github.com/nix-rust/nix/pull/311)) -- Added `EPOLLEXCLUSIVE` to `EpollEventKind` in `::nix::sys::epoll`. - ([#330](https://github.com/nix-rust/nix/pull/330)) -- Added `pause` to `::nix::unistd`. - ([#336](https://github.com/nix-rust/nix/pull/336)) -- Added `sleep` to `::nix::unistd`. - ([#351](https://github.com/nix-rust/nix/pull/351)) -- Added `S_IFDIR`, `S_IFLNK`, `S_IFMT` to `SFlag` in `::nix::sys::stat`. - ([#359](https://github.com/nix-rust/nix/pull/359)) -- Added `clear` and `extend` functions to `SigSet`'s implementation in - `::nix::sys::signal`. - ([#347](https://github.com/nix-rust/nix/pull/347)) -- `sockaddr_storage_to_addr` in `::nix::sys::socket` now supports `sockaddr_nl` - on _linux_ and _android_. - ([#366](https://github.com/nix-rust/nix/pull/366)) -- Added support for `SO_ORIGINAL_DST` in `::nix::sys::socket` on _linux_. - ([#367](https://github.com/nix-rust/nix/pull/367)) -- Added `SIGINFO` in `::nix::sys::signal` for the _macos_ target as well as - `SIGPWR` and `SIGSTKFLT` in `::nix::sys::signal` for non-_macos_ targets. - ([#361](https://github.com/nix-rust/nix/pull/361)) - -### Changed -- Changed the structure `IoVec` in `::nix::sys::uio`. - ([#304](https://github.com/nix-rust/nix/pull/304)) -- Replaced `CREATE_NEW_FD` by `SIGNALFD_NEW` in `::nix::sys::signalfd`. - ([#309](https://github.com/nix-rust/nix/pull/309)) -- Renamed `SaFlag` to `SaFlags` and `SigFlag` to `SigFlags` in - `::nix::sys::signal`. - ([#314](https://github.com/nix-rust/nix/pull/314)) -- Renamed `Fork` to `ForkResult` and changed its fields in `::nix::unistd`. - ([#332](https://github.com/nix-rust/nix/pull/332)) -- Added the `signal` parameter to `clone`'s signature in `::nix::sched`. - ([#344](https://github.com/nix-rust/nix/pull/344)) -- `execv`, `execve`, and `execvp` now return `Result<Void>` instead of - `Result<()>` in `::nix::unistd`. - ([#357](https://github.com/nix-rust/nix/pull/357)) - -### Fixed -- Improved the conversion from `std::net::SocketAddr` to `InetAddr` in - `::nix::sys::socket::addr`. - ([#335](https://github.com/nix-rust/nix/pull/335)) - -## [0.5.0] 2016-03-01 diff --git a/vendor/nix/Cargo.toml b/vendor/nix/Cargo.toml deleted file mode 100644 index 0afc445c2..000000000 --- a/vendor/nix/Cargo.toml +++ /dev/null @@ -1,185 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies. -# -# If you are reading this file be aware that the original Cargo.toml -# will likely look very different (and much more reasonable). -# See Cargo.toml.orig for the original contents. - -[package] -edition = "2018" -rust-version = "1.56" -name = "nix" -version = "0.26.2" -authors = ["The nix-rust Project Developers"] -include = [ - "src/**/*", - "test/**/*", - "LICENSE", - "README.md", - "CHANGELOG.md", -] -description = "Rust friendly bindings to *nix APIs" -readme = "README.md" -categories = ["os::unix-apis"] -license = "MIT" -repository = "https://github.com/nix-rust/nix" - -[package.metadata.docs.rs] -rustdoc-args = [ - "--cfg", - "docsrs", -] -targets = [ - "x86_64-unknown-linux-gnu", - "aarch64-linux-android", - "x86_64-apple-darwin", - "aarch64-apple-ios", - "x86_64-unknown-freebsd", - "x86_64-unknown-openbsd", - "x86_64-unknown-netbsd", - "x86_64-unknown-dragonfly", - "x86_64-fuchsia", - "x86_64-unknown-redox", - "x86_64-unknown-illumos", -] - -[[test]] -name = "test" -path = "test/test.rs" - -[[test]] -name = "test-aio-drop" -path = "test/sys/test_aio_drop.rs" - -[[test]] -name = "test-clearenv" -path = "test/test_clearenv.rs" - -[[test]] -name = "test-mount" -path = "test/test_mount.rs" -harness = false - -[[test]] -name = "test-ptymaster-drop" -path = "test/test_ptymaster_drop.rs" - -[dependencies.bitflags] -version = "1.1" - -[dependencies.cfg-if] -version = "1.0" - -[dependencies.libc] -version = "0.2.137" -features = ["extra_traits"] - -[dependencies.pin-utils] -version = "0.1.0" -optional = true - -[dependencies.static_assertions] -version = "1" - -[dev-dependencies.assert-impl] -version = "0.1" - -[dev-dependencies.lazy_static] -version = "1.4" - -[dev-dependencies.parking_lot] -version = "0.12" - -[dev-dependencies.rand] -version = "0.8" - -[dev-dependencies.semver] -version = "1.0.7" - -[dev-dependencies.tempfile] -version = "3.3.0" - -[features] -acct = [] -aio = ["pin-utils"] -default = [ - "acct", - "aio", - "dir", - "env", - "event", - "feature", - "fs", - "hostname", - "inotify", - "ioctl", - "kmod", - "mman", - "mount", - "mqueue", - "net", - "personality", - "poll", - "process", - "pthread", - "ptrace", - "quota", - "reboot", - "resource", - "sched", - "signal", - "socket", - "term", - "time", - "ucontext", - "uio", - "user", - "zerocopy", -] -dir = ["fs"] -env = [] -event = [] -feature = [] -fs = [] -hostname = [] -inotify = [] -ioctl = [] -kmod = [] -mman = [] -mount = ["uio"] -mqueue = ["fs"] -net = ["socket"] -personality = [] -poll = [] -process = [] -pthread = [] -ptrace = ["process"] -quota = [] -reboot = [] -resource = [] -sched = ["process"] -signal = ["process"] -socket = ["memoffset"] -term = [] -time = [] -ucontext = ["signal"] -uio = [] -user = ["feature"] -zerocopy = [ - "fs", - "uio", -] - -[target."cfg(any(target_os = \"android\", target_os = \"linux\"))".dev-dependencies.caps] -version = "0.5.3" - -[target."cfg(not(target_os = \"redox\"))".dependencies.memoffset] -version = "0.7" -optional = true - -[target."cfg(target_os = \"freebsd\")".dev-dependencies.sysctl] -version = "0.4" diff --git a/vendor/nix/LICENSE b/vendor/nix/LICENSE deleted file mode 100644 index aff9096fd..000000000 --- a/vendor/nix/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Carl Lerche + nix-rust Authors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/vendor/nix/README.md b/vendor/nix/README.md deleted file mode 100644 index 2c42b905f..000000000 --- a/vendor/nix/README.md +++ /dev/null @@ -1,105 +0,0 @@ -# Rust bindings to *nix APIs - -[![Cirrus Build Status](https://api.cirrus-ci.com/github/nix-rust/nix.svg)](https://cirrus-ci.com/github/nix-rust/nix) -[![crates.io](https://img.shields.io/crates/v/nix.svg)](https://crates.io/crates/nix) - -[Documentation (Releases)](https://docs.rs/nix/) - -Nix seeks to provide friendly bindings to various *nix platform APIs (Linux, Darwin, -...). The goal is to not provide a 100% unified interface, but to unify -what can be while still providing platform specific APIs. - -For many system APIs, Nix provides a safe alternative to the unsafe APIs -exposed by the [libc crate](https://github.com/rust-lang/libc). This is done by -wrapping the libc functionality with types/abstractions that enforce legal/safe -usage. - - -As an example of what Nix provides, examine the differences between what is -exposed by libc and nix for the -[gethostname](https://man7.org/linux/man-pages/man2/gethostname.2.html) system -call: - -```rust,ignore -// libc api (unsafe, requires handling return code/errno) -pub unsafe extern fn gethostname(name: *mut c_char, len: size_t) -> c_int; - -// nix api (returns a nix::Result<OsString>) -pub fn gethostname() -> Result<OsString>; -``` - -## Supported Platforms - -nix target support consists of two tiers. While nix attempts to support all -platforms supported by [libc](https://github.com/rust-lang/libc), only some -platforms are actively supported due to either technical or manpower -limitations. Support for platforms is split into three tiers: - - * Tier 1 - Builds and tests for this target are run in CI. Failures of either - block the inclusion of new code. - * Tier 2 - Builds for this target are run in CI. Failures during the build - blocks the inclusion of new code. Tests may be run, but failures - in tests don't block the inclusion of new code. - * Tier 3 - Builds for this target are run in CI. Failures during the build - *do not* block the inclusion of new code. Testing may be run, but - failures in tests don't block the inclusion of new code. - -The following targets are supported by `nix`: - -Tier 1: - * aarch64-apple-darwin - * aarch64-unknown-linux-gnu - * arm-unknown-linux-gnueabi - * armv7-unknown-linux-gnueabihf - * i686-unknown-freebsd - * i686-unknown-linux-gnu - * i686-unknown-linux-musl - * mips-unknown-linux-gnu - * mips64-unknown-linux-gnuabi64 - * mips64el-unknown-linux-gnuabi64 - * mipsel-unknown-linux-gnu - * powerpc64le-unknown-linux-gnu - * x86_64-unknown-freebsd - * x86_64-unknown-linux-gnu - * x86_64-unknown-linux-musl - -Tier 2: - * aarch64-apple-ios - * aarch64-linux-android - * arm-linux-androideabi - * arm-unknown-linux-musleabi - * armv7-linux-androideabi - * i686-linux-android - * powerpc-unknown-linux-gnu - * s390x-unknown-linux-gnu - * x86_64-apple-ios - * x86_64-linux-android - * x86_64-apple-darwin - * x86_64-unknown-illumos - * x86_64-unknown-netbsd - -Tier 3: - * armv7-unknown-linux-uclibceabihf - * x86_64-fuchsia - * x86_64-unknown-dragonfly - * x86_64-unknown-haiku - * x86_64-unknown-linux-gnux32 - * x86_64-unknown-openbsd - * x86_64-unknown-redox - -## Minimum Supported Rust Version (MSRV) - -nix is supported on Rust 1.56.1 and higher. Its MSRV will not be -changed in the future without bumping the major or minor version. - -## Contributing - -Contributions are very welcome. Please See [CONTRIBUTING](CONTRIBUTING.md) for -additional details. - -Feel free to join us in [the nix-rust/nix](https://gitter.im/nix-rust/nix) channel on Gitter to -discuss `nix` development. - -## License - -Nix is licensed under the MIT license. See [LICENSE](LICENSE) for more details. diff --git a/vendor/nix/src/dir.rs b/vendor/nix/src/dir.rs deleted file mode 100644 index 5ce503644..000000000 --- a/vendor/nix/src/dir.rs +++ /dev/null @@ -1,276 +0,0 @@ -//! List directory contents - -use crate::errno::Errno; -use crate::fcntl::{self, OFlag}; -use crate::sys; -use crate::{Error, NixPath, Result}; -use cfg_if::cfg_if; -use std::ffi; -use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd}; -use std::ptr; - -#[cfg(target_os = "linux")] -use libc::{dirent64 as dirent, readdir64_r as readdir_r}; - -#[cfg(not(target_os = "linux"))] -use libc::{dirent, readdir_r}; - -/// An open directory. -/// -/// This is a lower-level interface than `std::fs::ReadDir`. Notable differences: -/// * can be opened from a file descriptor (as returned by `openat`, perhaps before knowing -/// if the path represents a file or directory). -/// * implements `AsRawFd`, so it can be passed to `fstat`, `openat`, etc. -/// The file descriptor continues to be owned by the `Dir`, so callers must not keep a `RawFd` -/// after the `Dir` is dropped. -/// * can be iterated through multiple times without closing and reopening the file -/// descriptor. Each iteration rewinds when finished. -/// * returns entries for `.` (current directory) and `..` (parent directory). -/// * returns entries' names as a `CStr` (no allocation or conversion beyond whatever libc -/// does). -#[derive(Debug, Eq, Hash, PartialEq)] -pub struct Dir(ptr::NonNull<libc::DIR>); - -impl Dir { - /// Opens the given path as with `fcntl::open`. - pub fn open<P: ?Sized + NixPath>( - path: &P, - oflag: OFlag, - mode: sys::stat::Mode, - ) -> Result<Self> { - let fd = fcntl::open(path, oflag, mode)?; - Dir::from_fd(fd) - } - - /// Opens the given path as with `fcntl::openat`. - pub fn openat<P: ?Sized + NixPath>( - dirfd: RawFd, - path: &P, - oflag: OFlag, - mode: sys::stat::Mode, - ) -> Result<Self> { - let fd = fcntl::openat(dirfd, path, oflag, mode)?; - Dir::from_fd(fd) - } - - /// Converts from a descriptor-based object, closing the descriptor on success or failure. - #[inline] - pub fn from<F: IntoRawFd>(fd: F) -> Result<Self> { - Dir::from_fd(fd.into_raw_fd()) - } - - /// Converts from a file descriptor, closing it on success or failure. - #[doc(alias("fdopendir"))] - pub fn from_fd(fd: RawFd) -> Result<Self> { - let d = ptr::NonNull::new(unsafe { libc::fdopendir(fd) }).ok_or_else( - || { - let e = Error::last(); - unsafe { libc::close(fd) }; - e - }, - )?; - Ok(Dir(d)) - } - - /// Returns an iterator of `Result<Entry>` which rewinds when finished. - pub fn iter(&mut self) -> Iter { - Iter(self) - } -} - -// `Dir` is not `Sync`. With the current implementation, it could be, but according to -// https://www.gnu.org/software/libc/manual/html_node/Reading_002fClosing-Directory.html, -// future versions of POSIX are likely to obsolete `readdir_r` and specify that it's unsafe to -// call `readdir` simultaneously from multiple threads. -// -// `Dir` is safe to pass from one thread to another, as it's not reference-counted. -unsafe impl Send for Dir {} - -impl AsRawFd for Dir { - fn as_raw_fd(&self) -> RawFd { - unsafe { libc::dirfd(self.0.as_ptr()) } - } -} - -impl Drop for Dir { - fn drop(&mut self) { - let e = Errno::result(unsafe { libc::closedir(self.0.as_ptr()) }); - if !std::thread::panicking() && e == Err(Errno::EBADF) { - panic!("Closing an invalid file descriptor!"); - }; - } -} - -fn next(dir: &mut Dir) -> Option<Result<Entry>> { - unsafe { - // Note: POSIX specifies that portable applications should dynamically allocate a - // buffer with room for a `d_name` field of size `pathconf(..., _PC_NAME_MAX)` plus 1 - // for the NUL byte. It doesn't look like the std library does this; it just uses - // fixed-sized buffers (and libc's dirent seems to be sized so this is appropriate). - // Probably fine here too then. - let mut ent = std::mem::MaybeUninit::<dirent>::uninit(); - let mut result = ptr::null_mut(); - if let Err(e) = Errno::result(readdir_r( - dir.0.as_ptr(), - ent.as_mut_ptr(), - &mut result, - )) { - return Some(Err(e)); - } - if result.is_null() { - return None; - } - assert_eq!(result, ent.as_mut_ptr()); - Some(Ok(Entry(ent.assume_init()))) - } -} - -/// Return type of [`Dir::iter`]. -#[derive(Debug, Eq, Hash, PartialEq)] -pub struct Iter<'d>(&'d mut Dir); - -impl<'d> Iterator for Iter<'d> { - type Item = Result<Entry>; - - fn next(&mut self) -> Option<Self::Item> { - next(self.0) - } -} - -impl<'d> Drop for Iter<'d> { - fn drop(&mut self) { - unsafe { libc::rewinddir((self.0).0.as_ptr()) } - } -} - -/// The return type of [Dir::into_iter] -#[derive(Debug, Eq, Hash, PartialEq)] -pub struct OwningIter(Dir); - -impl Iterator for OwningIter { - type Item = Result<Entry>; - - fn next(&mut self) -> Option<Self::Item> { - next(&mut self.0) - } -} - -/// The file descriptor continues to be owned by the `OwningIter`, -/// so callers must not keep a `RawFd` after the `OwningIter` is dropped. -impl AsRawFd for OwningIter { - fn as_raw_fd(&self) -> RawFd { - self.0.as_raw_fd() - } -} - -impl IntoIterator for Dir { - type Item = Result<Entry>; - type IntoIter = OwningIter; - - /// Creates a owning iterator, that is, one that takes ownership of the - /// `Dir`. The `Dir` cannot be used after calling this. This can be useful - /// when you have a function that both creates a `Dir` instance and returns - /// an `Iterator`. - /// - /// Example: - /// - /// ``` - /// use nix::{dir::Dir, fcntl::OFlag, sys::stat::Mode}; - /// use std::{iter::Iterator, string::String}; - /// - /// fn ls_upper(dirname: &str) -> impl Iterator<Item=String> { - /// let d = Dir::open(dirname, OFlag::O_DIRECTORY, Mode::S_IXUSR).unwrap(); - /// d.into_iter().map(|x| x.unwrap().file_name().as_ref().to_string_lossy().to_ascii_uppercase()) - /// } - /// ``` - fn into_iter(self) -> Self::IntoIter { - OwningIter(self) - } -} - -/// A directory entry, similar to `std::fs::DirEntry`. -/// -/// Note that unlike the std version, this may represent the `.` or `..` entries. -#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)] -#[repr(transparent)] -pub struct Entry(dirent); - -/// Type of file referenced by a directory entry -#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)] -pub enum Type { - /// FIFO (Named pipe) - Fifo, - /// Character device - CharacterDevice, - /// Directory - Directory, - /// Block device - BlockDevice, - /// Regular file - File, - /// Symbolic link - Symlink, - /// Unix-domain socket - Socket, -} - -impl Entry { - /// Returns the inode number (`d_ino`) of the underlying `dirent`. - #[allow(clippy::useless_conversion)] // Not useless on all OSes - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - pub fn ino(&self) -> u64 { - cfg_if! { - if #[cfg(any(target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "ios", - target_os = "l4re", - target_os = "linux", - target_os = "macos", - target_os = "solaris"))] { - self.0.d_ino as u64 - } else { - u64::from(self.0.d_fileno) - } - } - } - - /// Returns the bare file name of this directory entry without any other leading path component. - pub fn file_name(&self) -> &ffi::CStr { - unsafe { ::std::ffi::CStr::from_ptr(self.0.d_name.as_ptr()) } - } - - /// Returns the type of this directory entry, if known. - /// - /// See platform `readdir(3)` or `dirent(5)` manpage for when the file type is known; - /// notably, some Linux filesystems don't implement this. The caller should use `stat` or - /// `fstat` if this returns `None`. - pub fn file_type(&self) -> Option<Type> { - #[cfg(not(any( - target_os = "illumos", - target_os = "solaris", - target_os = "haiku" - )))] - match self.0.d_type { - libc::DT_FIFO => Some(Type::Fifo), - libc::DT_CHR => Some(Type::CharacterDevice), - libc::DT_DIR => Some(Type::Directory), - libc::DT_BLK => Some(Type::BlockDevice), - libc::DT_REG => Some(Type::File), - libc::DT_LNK => Some(Type::Symlink), - libc::DT_SOCK => Some(Type::Socket), - /* libc::DT_UNKNOWN | */ _ => None, - } - - // illumos, Solaris, and Haiku systems do not have the d_type member at all: - #[cfg(any( - target_os = "illumos", - target_os = "solaris", - target_os = "haiku" - ))] - None - } -} diff --git a/vendor/nix/src/env.rs b/vendor/nix/src/env.rs deleted file mode 100644 index 95177a1d2..000000000 --- a/vendor/nix/src/env.rs +++ /dev/null @@ -1,64 +0,0 @@ -//! Environment variables -use cfg_if::cfg_if; -use std::fmt; - -/// Indicates that [`clearenv`] failed for some unknown reason -#[derive(Clone, Copy, Debug)] -pub struct ClearEnvError; - -impl fmt::Display for ClearEnvError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "clearenv failed") - } -} - -impl std::error::Error for ClearEnvError {} - -/// Clear the environment of all name-value pairs. -/// -/// On platforms where libc provides `clearenv()`, it will be used. libc's -/// `clearenv()` is documented to return an error code but not set errno; if the -/// return value indicates a failure, this function will return -/// [`ClearEnvError`]. -/// -/// On platforms where libc does not provide `clearenv()`, a fallback -/// implementation will be used that iterates over all environment variables and -/// removes them one-by-one. -/// -/// # Safety -/// -/// This function is not threadsafe and can cause undefined behavior in -/// combination with `std::env` or other program components that access the -/// environment. See, for example, the discussion on `std::env::remove_var`; this -/// function is a case of an "inherently unsafe non-threadsafe API" dealing with -/// the environment. -/// -/// The caller must ensure no other threads access the process environment while -/// this function executes and that no raw pointers to an element of libc's -/// `environ` is currently held. The latter is not an issue if the only other -/// environment access in the program is via `std::env`, but the requirement on -/// thread safety must still be upheld. -pub unsafe fn clearenv() -> std::result::Result<(), ClearEnvError> { - cfg_if! { - if #[cfg(any(target_os = "fuchsia", - target_os = "wasi", - target_env = "uclibc", - target_os = "linux", - target_os = "android", - target_os = "emscripten"))] { - let ret = libc::clearenv(); - } else { - use std::env; - for (name, _) in env::vars_os() { - env::remove_var(name); - } - let ret = 0; - } - } - - if ret == 0 { - Ok(()) - } else { - Err(ClearEnvError) - } -} diff --git a/vendor/nix/src/errno.rs b/vendor/nix/src/errno.rs deleted file mode 100644 index d8ad28de8..000000000 --- a/vendor/nix/src/errno.rs +++ /dev/null @@ -1,3133 +0,0 @@ -use crate::Result; -use cfg_if::cfg_if; -use libc::{c_int, c_void}; -use std::convert::TryFrom; -use std::{error, fmt, io}; - -pub use self::consts::*; - -cfg_if! { - if #[cfg(any(target_os = "freebsd", - target_os = "ios", - target_os = "macos"))] { - unsafe fn errno_location() -> *mut c_int { - libc::__error() - } - } else if #[cfg(any(target_os = "android", - target_os = "netbsd", - target_os = "openbsd"))] { - unsafe fn errno_location() -> *mut c_int { - libc::__errno() - } - } else if #[cfg(any(target_os = "linux", - target_os = "redox", - target_os = "dragonfly", - target_os = "fuchsia"))] { - unsafe fn errno_location() -> *mut c_int { - libc::__errno_location() - } - } else if #[cfg(any(target_os = "illumos", target_os = "solaris"))] { - unsafe fn errno_location() -> *mut c_int { - libc::___errno() - } - } else if #[cfg(any(target_os = "haiku",))] { - unsafe fn errno_location() -> *mut c_int { - libc::_errnop() - } - } -} - -/// Sets the platform-specific errno to no-error -fn clear() { - // Safe because errno is a thread-local variable - unsafe { - *errno_location() = 0; - } -} - -/// Returns the platform-specific value of errno -pub fn errno() -> i32 { - unsafe { *errno_location() } -} - -impl Errno { - pub fn last() -> Self { - last() - } - - pub fn desc(self) -> &'static str { - desc(self) - } - - pub const fn from_i32(err: i32) -> Errno { - from_i32(err) - } - - pub fn clear() { - clear() - } - - /// Returns `Ok(value)` if it does not contain the sentinel value. This - /// should not be used when `-1` is not the errno sentinel value. - #[inline] - pub fn result<S: ErrnoSentinel + PartialEq<S>>(value: S) -> Result<S> { - if value == S::sentinel() { - Err(Self::last()) - } else { - Ok(value) - } - } -} - -/// The sentinel value indicates that a function failed and more detailed -/// information about the error can be found in `errno` -pub trait ErrnoSentinel: Sized { - fn sentinel() -> Self; -} - -impl ErrnoSentinel for isize { - fn sentinel() -> Self { - -1 - } -} - -impl ErrnoSentinel for i32 { - fn sentinel() -> Self { - -1 - } -} - -impl ErrnoSentinel for i64 { - fn sentinel() -> Self { - -1 - } -} - -impl ErrnoSentinel for *mut c_void { - fn sentinel() -> Self { - -1isize as *mut c_void - } -} - -impl ErrnoSentinel for libc::sighandler_t { - fn sentinel() -> Self { - libc::SIG_ERR - } -} - -impl error::Error for Errno {} - -impl fmt::Display for Errno { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}: {}", self, self.desc()) - } -} - -impl From<Errno> for io::Error { - fn from(err: Errno) -> Self { - io::Error::from_raw_os_error(err as i32) - } -} - -impl TryFrom<io::Error> for Errno { - type Error = io::Error; - - fn try_from(ioerror: io::Error) -> std::result::Result<Self, io::Error> { - ioerror.raw_os_error().map(Errno::from_i32).ok_or(ioerror) - } -} - -fn last() -> Errno { - Errno::from_i32(errno()) -} - -fn desc(errno: Errno) -> &'static str { - use self::Errno::*; - match errno { - UnknownErrno => "Unknown errno", - EPERM => "Operation not permitted", - ENOENT => "No such file or directory", - ESRCH => "No such process", - EINTR => "Interrupted system call", - EIO => "I/O error", - ENXIO => "No such device or address", - E2BIG => "Argument list too long", - ENOEXEC => "Exec format error", - EBADF => "Bad file number", - ECHILD => "No child processes", - EAGAIN => "Try again", - ENOMEM => "Out of memory", - EACCES => "Permission denied", - EFAULT => "Bad address", - #[cfg(not(target_os = "haiku"))] - ENOTBLK => "Block device required", - EBUSY => "Device or resource busy", - EEXIST => "File exists", - EXDEV => "Cross-device link", - ENODEV => "No such device", - ENOTDIR => "Not a directory", - EISDIR => "Is a directory", - EINVAL => "Invalid argument", - ENFILE => "File table overflow", - EMFILE => "Too many open files", - ENOTTY => "Not a typewriter", - ETXTBSY => "Text file busy", - EFBIG => "File too large", - ENOSPC => "No space left on device", - ESPIPE => "Illegal seek", - EROFS => "Read-only file system", - EMLINK => "Too many links", - EPIPE => "Broken pipe", - EDOM => "Math argument out of domain of func", - ERANGE => "Math result not representable", - EDEADLK => "Resource deadlock would occur", - ENAMETOOLONG => "File name too long", - ENOLCK => "No record locks available", - ENOSYS => "Function not implemented", - ENOTEMPTY => "Directory not empty", - ELOOP => "Too many symbolic links encountered", - ENOMSG => "No message of desired type", - EIDRM => "Identifier removed", - EINPROGRESS => "Operation now in progress", - EALREADY => "Operation already in progress", - ENOTSOCK => "Socket operation on non-socket", - EDESTADDRREQ => "Destination address required", - EMSGSIZE => "Message too long", - EPROTOTYPE => "Protocol wrong type for socket", - ENOPROTOOPT => "Protocol not available", - EPROTONOSUPPORT => "Protocol not supported", - #[cfg(not(target_os = "haiku"))] - ESOCKTNOSUPPORT => "Socket type not supported", - #[cfg(not(target_os = "haiku"))] - EPFNOSUPPORT => "Protocol family not supported", - #[cfg(not(target_os = "haiku"))] - EAFNOSUPPORT => "Address family not supported by protocol", - EADDRINUSE => "Address already in use", - EADDRNOTAVAIL => "Cannot assign requested address", - ENETDOWN => "Network is down", - ENETUNREACH => "Network is unreachable", - ENETRESET => "Network dropped connection because of reset", - ECONNABORTED => "Software caused connection abort", - ECONNRESET => "Connection reset by peer", - ENOBUFS => "No buffer space available", - EISCONN => "Transport endpoint is already connected", - ENOTCONN => "Transport endpoint is not connected", - ESHUTDOWN => "Cannot send after transport endpoint shutdown", - #[cfg(not(target_os = "haiku"))] - ETOOMANYREFS => "Too many references: cannot splice", - ETIMEDOUT => "Connection timed out", - ECONNREFUSED => "Connection refused", - EHOSTDOWN => "Host is down", - EHOSTUNREACH => "No route to host", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - ECHRNG => "Channel number out of range", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - EL2NSYNC => "Level 2 not synchronized", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - EL3HLT => "Level 3 halted", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - EL3RST => "Level 3 reset", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - ELNRNG => "Link number out of range", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - EUNATCH => "Protocol driver not attached", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - ENOCSI => "No CSI structure available", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - EL2HLT => "Level 2 halted", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - EBADE => "Invalid exchange", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - EBADR => "Invalid request descriptor", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - EXFULL => "Exchange full", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - ENOANO => "No anode", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - EBADRQC => "Invalid request code", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - EBADSLT => "Invalid slot", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - EBFONT => "Bad font file format", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - ENOSTR => "Device not a stream", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - ENODATA => "No data available", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - ETIME => "Timer expired", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - ENOSR => "Out of streams resources", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - ENONET => "Machine is not on the network", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - ENOPKG => "Package not installed", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - EREMOTE => "Object is remote", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - ENOLINK => "Link has been severed", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - EADV => "Advertise error", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - ESRMNT => "Srmount error", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - ECOMM => "Communication error on send", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - EPROTO => "Protocol error", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - EMULTIHOP => "Multihop attempted", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] - EDOTDOT => "RFS specific error", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] - EBADMSG => "Not a data message", - - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - EBADMSG => "Trying to read unreadable message", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia", - target_os = "haiku" - ))] - EOVERFLOW => "Value too large for defined data type", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - ENOTUNIQ => "Name not unique on network", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - EBADFD => "File descriptor in bad state", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - EREMCHG => "Remote address changed", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - ELIBACC => "Can not access a needed shared library", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - ELIBBAD => "Accessing a corrupted shared library", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - ELIBSCN => ".lib section in a.out corrupted", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - ELIBMAX => "Attempting to link in too many shared libraries", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - ELIBEXEC => "Cannot exec a shared library directly", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia", - target_os = "openbsd" - ))] - EILSEQ => "Illegal byte sequence", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - ERESTART => "Interrupted system call should be restarted", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - ESTRPIPE => "Streams pipe error", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] - EUSERS => "Too many users", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia", - target_os = "netbsd", - target_os = "redox" - ))] - EOPNOTSUPP => "Operation not supported on transport endpoint", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] - ESTALE => "Stale file handle", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] - EUCLEAN => "Structure needs cleaning", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] - ENOTNAM => "Not a XENIX named type file", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] - ENAVAIL => "No XENIX semaphores available", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] - EISNAM => "Is a named type file", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] - EREMOTEIO => "Remote I/O error", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] - EDQUOT => "Quota exceeded", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia", - target_os = "openbsd", - target_os = "dragonfly" - ))] - ENOMEDIUM => "No medium found", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia", - target_os = "openbsd" - ))] - EMEDIUMTYPE => "Wrong medium type", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia", - target_os = "haiku" - ))] - ECANCELED => "Operation canceled", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] - ENOKEY => "Required key not available", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] - EKEYEXPIRED => "Key has expired", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] - EKEYREVOKED => "Key has been revoked", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] - EKEYREJECTED => "Key was rejected by service", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] - EOWNERDEAD => "Owner died", - - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - EOWNERDEAD => "Process died with lock", - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] - ENOTRECOVERABLE => "State not recoverable", - - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - ENOTRECOVERABLE => "Lock is not recoverable", - - #[cfg(any( - all(target_os = "linux", not(target_arch = "mips")), - target_os = "fuchsia" - ))] - ERFKILL => "Operation not possible due to RF-kill", - - #[cfg(any( - all(target_os = "linux", not(target_arch = "mips")), - target_os = "fuchsia" - ))] - EHWPOISON => "Memory page has hardware error", - - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - EDOOFUS => "Programming error", - - #[cfg(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "redox" - ))] - EMULTIHOP => "Multihop attempted", - - #[cfg(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "redox" - ))] - ENOLINK => "Link has been severed", - - #[cfg(target_os = "freebsd")] - ENOTCAPABLE => "Capabilities insufficient", - - #[cfg(target_os = "freebsd")] - ECAPMODE => "Not permitted in capability mode", - - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd" - ))] - ENEEDAUTH => "Need authenticator", - - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd", - target_os = "redox", - target_os = "illumos", - target_os = "solaris" - ))] - EOVERFLOW => "Value too large to be stored in data type", - - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "netbsd", - target_os = "redox", - target_os = "haiku" - ))] - EILSEQ => "Illegal byte sequence", - - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd", - target_os = "haiku" - ))] - ENOATTR => "Attribute not found", - - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd", - target_os = "redox", - target_os = "haiku" - ))] - EBADMSG => "Bad message", - - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd", - target_os = "redox", - target_os = "haiku" - ))] - EPROTO => "Protocol error", - - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd" - ))] - ENOTRECOVERABLE => "State not recoverable", - - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd" - ))] - EOWNERDEAD => "Previous owner died", - - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd", - target_os = "illumos", - target_os = "solaris", - target_os = "haiku" - ))] - ENOTSUP => "Operation not supported", - - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd" - ))] - EPROCLIM => "Too many processes", - - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd", - target_os = "redox" - ))] - EUSERS => "Too many users", - - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd", - target_os = "redox", - target_os = "illumos", - target_os = "solaris", - target_os = "haiku" - ))] - EDQUOT => "Disc quota exceeded", - - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd", - target_os = "redox", - target_os = "illumos", - target_os = "solaris", - target_os = "haiku" - ))] - ESTALE => "Stale NFS file handle", - - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd", - target_os = "redox" - ))] - EREMOTE => "Too many levels of remote in path", - - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd" - ))] - EBADRPC => "RPC struct is bad", - - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd" - ))] - ERPCMISMATCH => "RPC version wrong", - - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd" - ))] - EPROGUNAVAIL => "RPC prog. not avail", - - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd" - ))] - EPROGMISMATCH => "Program version wrong", - - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd" - ))] - EPROCUNAVAIL => "Bad procedure for program", - - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd" - ))] - EFTYPE => "Inappropriate file type or format", - - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd" - ))] - EAUTH => "Authentication error", - - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd", - target_os = "redox" - ))] - ECANCELED => "Operation canceled", - - #[cfg(any(target_os = "macos", target_os = "ios"))] - EPWROFF => "Device power is off", - - #[cfg(any(target_os = "macos", target_os = "ios"))] - EDEVERR => "Device error, e.g. paper out", - - #[cfg(any(target_os = "macos", target_os = "ios"))] - EBADEXEC => "Bad executable", - - #[cfg(any(target_os = "macos", target_os = "ios"))] - EBADARCH => "Bad CPU type in executable", - - #[cfg(any(target_os = "macos", target_os = "ios"))] - ESHLIBVERS => "Shared library version mismatch", - - #[cfg(any(target_os = "macos", target_os = "ios"))] - EBADMACHO => "Malformed Macho file", - - #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "netbsd", - target_os = "haiku" - ))] - EMULTIHOP => "Reserved", - - #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "netbsd", - target_os = "redox" - ))] - ENODATA => "No message available on STREAM", - - #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "netbsd", - target_os = "haiku" - ))] - ENOLINK => "Reserved", - - #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "netbsd", - target_os = "redox" - ))] - ENOSR => "No STREAM resources", - - #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "netbsd", - target_os = "redox" - ))] - ENOSTR => "Not a STREAM", - - #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "netbsd", - target_os = "redox" - ))] - ETIME => "STREAM ioctl timeout", - - #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "illumos", - target_os = "solaris" - ))] - EOPNOTSUPP => "Operation not supported on socket", - - #[cfg(any(target_os = "macos", target_os = "ios"))] - ENOPOLICY => "No such policy registered", - - #[cfg(any(target_os = "macos", target_os = "ios"))] - EQFULL => "Interface output queue is full", - - #[cfg(target_os = "openbsd")] - EOPNOTSUPP => "Operation not supported", - - #[cfg(target_os = "openbsd")] - EIPSEC => "IPsec processing failure", - - #[cfg(target_os = "dragonfly")] - EASYNC => "Async", - - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - EDEADLOCK => "Resource deadlock would occur", - - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - ELOCKUNMAPPED => "Locked lock was unmapped", - - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - ENOTACTIVE => "Facility is not active", - } -} - -#[cfg(any(target_os = "linux", target_os = "android", target_os = "fuchsia"))] -mod consts { - #[derive(Clone, Copy, Debug, Eq, PartialEq)] - #[repr(i32)] - #[non_exhaustive] - pub enum Errno { - UnknownErrno = 0, - EPERM = libc::EPERM, - ENOENT = libc::ENOENT, - ESRCH = libc::ESRCH, - EINTR = libc::EINTR, - EIO = libc::EIO, - ENXIO = libc::ENXIO, - E2BIG = libc::E2BIG, - ENOEXEC = libc::ENOEXEC, - EBADF = libc::EBADF, - ECHILD = libc::ECHILD, - EAGAIN = libc::EAGAIN, - ENOMEM = libc::ENOMEM, - EACCES = libc::EACCES, - EFAULT = libc::EFAULT, - ENOTBLK = libc::ENOTBLK, - EBUSY = libc::EBUSY, - EEXIST = libc::EEXIST, - EXDEV = libc::EXDEV, - ENODEV = libc::ENODEV, - ENOTDIR = libc::ENOTDIR, - EISDIR = libc::EISDIR, - EINVAL = libc::EINVAL, - ENFILE = libc::ENFILE, - EMFILE = libc::EMFILE, - ENOTTY = libc::ENOTTY, - ETXTBSY = libc::ETXTBSY, - EFBIG = libc::EFBIG, - ENOSPC = libc::ENOSPC, - ESPIPE = libc::ESPIPE, - EROFS = libc::EROFS, - EMLINK = libc::EMLINK, - EPIPE = libc::EPIPE, - EDOM = libc::EDOM, - ERANGE = libc::ERANGE, - EDEADLK = libc::EDEADLK, - ENAMETOOLONG = libc::ENAMETOOLONG, - ENOLCK = libc::ENOLCK, - ENOSYS = libc::ENOSYS, - ENOTEMPTY = libc::ENOTEMPTY, - ELOOP = libc::ELOOP, - ENOMSG = libc::ENOMSG, - EIDRM = libc::EIDRM, - ECHRNG = libc::ECHRNG, - EL2NSYNC = libc::EL2NSYNC, - EL3HLT = libc::EL3HLT, - EL3RST = libc::EL3RST, - ELNRNG = libc::ELNRNG, - EUNATCH = libc::EUNATCH, - ENOCSI = libc::ENOCSI, - EL2HLT = libc::EL2HLT, - EBADE = libc::EBADE, - EBADR = libc::EBADR, - EXFULL = libc::EXFULL, - ENOANO = libc::ENOANO, - EBADRQC = libc::EBADRQC, - EBADSLT = libc::EBADSLT, - EBFONT = libc::EBFONT, - ENOSTR = libc::ENOSTR, - ENODATA = libc::ENODATA, - ETIME = libc::ETIME, - ENOSR = libc::ENOSR, - ENONET = libc::ENONET, - ENOPKG = libc::ENOPKG, - EREMOTE = libc::EREMOTE, - ENOLINK = libc::ENOLINK, - EADV = libc::EADV, - ESRMNT = libc::ESRMNT, - ECOMM = libc::ECOMM, - EPROTO = libc::EPROTO, - EMULTIHOP = libc::EMULTIHOP, - EDOTDOT = libc::EDOTDOT, - EBADMSG = libc::EBADMSG, - EOVERFLOW = libc::EOVERFLOW, - ENOTUNIQ = libc::ENOTUNIQ, - EBADFD = libc::EBADFD, - EREMCHG = libc::EREMCHG, - ELIBACC = libc::ELIBACC, - ELIBBAD = libc::ELIBBAD, - ELIBSCN = libc::ELIBSCN, - ELIBMAX = libc::ELIBMAX, - ELIBEXEC = libc::ELIBEXEC, - EILSEQ = libc::EILSEQ, - ERESTART = libc::ERESTART, - ESTRPIPE = libc::ESTRPIPE, - EUSERS = libc::EUSERS, - ENOTSOCK = libc::ENOTSOCK, - EDESTADDRREQ = libc::EDESTADDRREQ, - EMSGSIZE = libc::EMSGSIZE, - EPROTOTYPE = libc::EPROTOTYPE, - ENOPROTOOPT = libc::ENOPROTOOPT, - EPROTONOSUPPORT = libc::EPROTONOSUPPORT, - ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT, - EOPNOTSUPP = libc::EOPNOTSUPP, - EPFNOSUPPORT = libc::EPFNOSUPPORT, - EAFNOSUPPORT = libc::EAFNOSUPPORT, - EADDRINUSE = libc::EADDRINUSE, - EADDRNOTAVAIL = libc::EADDRNOTAVAIL, - ENETDOWN = libc::ENETDOWN, - ENETUNREACH = libc::ENETUNREACH, - ENETRESET = libc::ENETRESET, - ECONNABORTED = libc::ECONNABORTED, - ECONNRESET = libc::ECONNRESET, - ENOBUFS = libc::ENOBUFS, - EISCONN = libc::EISCONN, - ENOTCONN = libc::ENOTCONN, - ESHUTDOWN = libc::ESHUTDOWN, - ETOOMANYREFS = libc::ETOOMANYREFS, - ETIMEDOUT = libc::ETIMEDOUT, - ECONNREFUSED = libc::ECONNREFUSED, - EHOSTDOWN = libc::EHOSTDOWN, - EHOSTUNREACH = libc::EHOSTUNREACH, - EALREADY = libc::EALREADY, - EINPROGRESS = libc::EINPROGRESS, - ESTALE = libc::ESTALE, - EUCLEAN = libc::EUCLEAN, - ENOTNAM = libc::ENOTNAM, - ENAVAIL = libc::ENAVAIL, - EISNAM = libc::EISNAM, - EREMOTEIO = libc::EREMOTEIO, - EDQUOT = libc::EDQUOT, - ENOMEDIUM = libc::ENOMEDIUM, - EMEDIUMTYPE = libc::EMEDIUMTYPE, - ECANCELED = libc::ECANCELED, - ENOKEY = libc::ENOKEY, - EKEYEXPIRED = libc::EKEYEXPIRED, - EKEYREVOKED = libc::EKEYREVOKED, - EKEYREJECTED = libc::EKEYREJECTED, - EOWNERDEAD = libc::EOWNERDEAD, - ENOTRECOVERABLE = libc::ENOTRECOVERABLE, - #[cfg(not(any(target_os = "android", target_arch = "mips")))] - ERFKILL = libc::ERFKILL, - #[cfg(not(any(target_os = "android", target_arch = "mips")))] - EHWPOISON = libc::EHWPOISON, - } - - impl Errno { - pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - pub const EDEADLOCK: Errno = Errno::EDEADLK; - pub const ENOTSUP: Errno = Errno::EOPNOTSUPP; - } - - pub const fn from_i32(e: i32) -> Errno { - use self::Errno::*; - - match e { - libc::EPERM => EPERM, - libc::ENOENT => ENOENT, - libc::ESRCH => ESRCH, - libc::EINTR => EINTR, - libc::EIO => EIO, - libc::ENXIO => ENXIO, - libc::E2BIG => E2BIG, - libc::ENOEXEC => ENOEXEC, - libc::EBADF => EBADF, - libc::ECHILD => ECHILD, - libc::EAGAIN => EAGAIN, - libc::ENOMEM => ENOMEM, - libc::EACCES => EACCES, - libc::EFAULT => EFAULT, - libc::ENOTBLK => ENOTBLK, - libc::EBUSY => EBUSY, - libc::EEXIST => EEXIST, - libc::EXDEV => EXDEV, - libc::ENODEV => ENODEV, - libc::ENOTDIR => ENOTDIR, - libc::EISDIR => EISDIR, - libc::EINVAL => EINVAL, - libc::ENFILE => ENFILE, - libc::EMFILE => EMFILE, - libc::ENOTTY => ENOTTY, - libc::ETXTBSY => ETXTBSY, - libc::EFBIG => EFBIG, - libc::ENOSPC => ENOSPC, - libc::ESPIPE => ESPIPE, - libc::EROFS => EROFS, - libc::EMLINK => EMLINK, - libc::EPIPE => EPIPE, - libc::EDOM => EDOM, - libc::ERANGE => ERANGE, - libc::EDEADLK => EDEADLK, - libc::ENAMETOOLONG => ENAMETOOLONG, - libc::ENOLCK => ENOLCK, - libc::ENOSYS => ENOSYS, - libc::ENOTEMPTY => ENOTEMPTY, - libc::ELOOP => ELOOP, - libc::ENOMSG => ENOMSG, - libc::EIDRM => EIDRM, - libc::ECHRNG => ECHRNG, - libc::EL2NSYNC => EL2NSYNC, - libc::EL3HLT => EL3HLT, - libc::EL3RST => EL3RST, - libc::ELNRNG => ELNRNG, - libc::EUNATCH => EUNATCH, - libc::ENOCSI => ENOCSI, - libc::EL2HLT => EL2HLT, - libc::EBADE => EBADE, - libc::EBADR => EBADR, - libc::EXFULL => EXFULL, - libc::ENOANO => ENOANO, - libc::EBADRQC => EBADRQC, - libc::EBADSLT => EBADSLT, - libc::EBFONT => EBFONT, - libc::ENOSTR => ENOSTR, - libc::ENODATA => ENODATA, - libc::ETIME => ETIME, - libc::ENOSR => ENOSR, - libc::ENONET => ENONET, - libc::ENOPKG => ENOPKG, - libc::EREMOTE => EREMOTE, - libc::ENOLINK => ENOLINK, - libc::EADV => EADV, - libc::ESRMNT => ESRMNT, - libc::ECOMM => ECOMM, - libc::EPROTO => EPROTO, - libc::EMULTIHOP => EMULTIHOP, - libc::EDOTDOT => EDOTDOT, - libc::EBADMSG => EBADMSG, - libc::EOVERFLOW => EOVERFLOW, - libc::ENOTUNIQ => ENOTUNIQ, - libc::EBADFD => EBADFD, - libc::EREMCHG => EREMCHG, - libc::ELIBACC => ELIBACC, - libc::ELIBBAD => ELIBBAD, - libc::ELIBSCN => ELIBSCN, - libc::ELIBMAX => ELIBMAX, - libc::ELIBEXEC => ELIBEXEC, - libc::EILSEQ => EILSEQ, - libc::ERESTART => ERESTART, - libc::ESTRPIPE => ESTRPIPE, - libc::EUSERS => EUSERS, - libc::ENOTSOCK => ENOTSOCK, - libc::EDESTADDRREQ => EDESTADDRREQ, - libc::EMSGSIZE => EMSGSIZE, - libc::EPROTOTYPE => EPROTOTYPE, - libc::ENOPROTOOPT => ENOPROTOOPT, - libc::EPROTONOSUPPORT => EPROTONOSUPPORT, - libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT, - libc::EOPNOTSUPP => EOPNOTSUPP, - libc::EPFNOSUPPORT => EPFNOSUPPORT, - libc::EAFNOSUPPORT => EAFNOSUPPORT, - libc::EADDRINUSE => EADDRINUSE, - libc::EADDRNOTAVAIL => EADDRNOTAVAIL, - libc::ENETDOWN => ENETDOWN, - libc::ENETUNREACH => ENETUNREACH, - libc::ENETRESET => ENETRESET, - libc::ECONNABORTED => ECONNABORTED, - libc::ECONNRESET => ECONNRESET, - libc::ENOBUFS => ENOBUFS, - libc::EISCONN => EISCONN, - libc::ENOTCONN => ENOTCONN, - libc::ESHUTDOWN => ESHUTDOWN, - libc::ETOOMANYREFS => ETOOMANYREFS, - libc::ETIMEDOUT => ETIMEDOUT, - libc::ECONNREFUSED => ECONNREFUSED, - libc::EHOSTDOWN => EHOSTDOWN, - libc::EHOSTUNREACH => EHOSTUNREACH, - libc::EALREADY => EALREADY, - libc::EINPROGRESS => EINPROGRESS, - libc::ESTALE => ESTALE, - libc::EUCLEAN => EUCLEAN, - libc::ENOTNAM => ENOTNAM, - libc::ENAVAIL => ENAVAIL, - libc::EISNAM => EISNAM, - libc::EREMOTEIO => EREMOTEIO, - libc::EDQUOT => EDQUOT, - libc::ENOMEDIUM => ENOMEDIUM, - libc::EMEDIUMTYPE => EMEDIUMTYPE, - libc::ECANCELED => ECANCELED, - libc::ENOKEY => ENOKEY, - libc::EKEYEXPIRED => EKEYEXPIRED, - libc::EKEYREVOKED => EKEYREVOKED, - libc::EKEYREJECTED => EKEYREJECTED, - libc::EOWNERDEAD => EOWNERDEAD, - libc::ENOTRECOVERABLE => ENOTRECOVERABLE, - #[cfg(not(any(target_os = "android", target_arch = "mips")))] - libc::ERFKILL => ERFKILL, - #[cfg(not(any(target_os = "android", target_arch = "mips")))] - libc::EHWPOISON => EHWPOISON, - _ => UnknownErrno, - } - } -} - -#[cfg(any(target_os = "macos", target_os = "ios"))] -mod consts { - #[derive(Clone, Copy, Debug, Eq, PartialEq)] - #[repr(i32)] - #[non_exhaustive] - pub enum Errno { - UnknownErrno = 0, - EPERM = libc::EPERM, - ENOENT = libc::ENOENT, - ESRCH = libc::ESRCH, - EINTR = libc::EINTR, - EIO = libc::EIO, - ENXIO = libc::ENXIO, - E2BIG = libc::E2BIG, - ENOEXEC = libc::ENOEXEC, - EBADF = libc::EBADF, - ECHILD = libc::ECHILD, - EDEADLK = libc::EDEADLK, - ENOMEM = libc::ENOMEM, - EACCES = libc::EACCES, - EFAULT = libc::EFAULT, - ENOTBLK = libc::ENOTBLK, - EBUSY = libc::EBUSY, - EEXIST = libc::EEXIST, - EXDEV = libc::EXDEV, - ENODEV = libc::ENODEV, - ENOTDIR = libc::ENOTDIR, - EISDIR = libc::EISDIR, - EINVAL = libc::EINVAL, - ENFILE = libc::ENFILE, - EMFILE = libc::EMFILE, - ENOTTY = libc::ENOTTY, - ETXTBSY = libc::ETXTBSY, - EFBIG = libc::EFBIG, - ENOSPC = libc::ENOSPC, - ESPIPE = libc::ESPIPE, - EROFS = libc::EROFS, - EMLINK = libc::EMLINK, - EPIPE = libc::EPIPE, - EDOM = libc::EDOM, - ERANGE = libc::ERANGE, - EAGAIN = libc::EAGAIN, - EINPROGRESS = libc::EINPROGRESS, - EALREADY = libc::EALREADY, - ENOTSOCK = libc::ENOTSOCK, - EDESTADDRREQ = libc::EDESTADDRREQ, - EMSGSIZE = libc::EMSGSIZE, - EPROTOTYPE = libc::EPROTOTYPE, - ENOPROTOOPT = libc::ENOPROTOOPT, - EPROTONOSUPPORT = libc::EPROTONOSUPPORT, - ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT, - ENOTSUP = libc::ENOTSUP, - EPFNOSUPPORT = libc::EPFNOSUPPORT, - EAFNOSUPPORT = libc::EAFNOSUPPORT, - EADDRINUSE = libc::EADDRINUSE, - EADDRNOTAVAIL = libc::EADDRNOTAVAIL, - ENETDOWN = libc::ENETDOWN, - ENETUNREACH = libc::ENETUNREACH, - ENETRESET = libc::ENETRESET, - ECONNABORTED = libc::ECONNABORTED, - ECONNRESET = libc::ECONNRESET, - ENOBUFS = libc::ENOBUFS, - EISCONN = libc::EISCONN, - ENOTCONN = libc::ENOTCONN, - ESHUTDOWN = libc::ESHUTDOWN, - ETOOMANYREFS = libc::ETOOMANYREFS, - ETIMEDOUT = libc::ETIMEDOUT, - ECONNREFUSED = libc::ECONNREFUSED, - ELOOP = libc::ELOOP, - ENAMETOOLONG = libc::ENAMETOOLONG, - EHOSTDOWN = libc::EHOSTDOWN, - EHOSTUNREACH = libc::EHOSTUNREACH, - ENOTEMPTY = libc::ENOTEMPTY, - EPROCLIM = libc::EPROCLIM, - EUSERS = libc::EUSERS, - EDQUOT = libc::EDQUOT, - ESTALE = libc::ESTALE, - EREMOTE = libc::EREMOTE, - EBADRPC = libc::EBADRPC, - ERPCMISMATCH = libc::ERPCMISMATCH, - EPROGUNAVAIL = libc::EPROGUNAVAIL, - EPROGMISMATCH = libc::EPROGMISMATCH, - EPROCUNAVAIL = libc::EPROCUNAVAIL, - ENOLCK = libc::ENOLCK, - ENOSYS = libc::ENOSYS, - EFTYPE = libc::EFTYPE, - EAUTH = libc::EAUTH, - ENEEDAUTH = libc::ENEEDAUTH, - EPWROFF = libc::EPWROFF, - EDEVERR = libc::EDEVERR, - EOVERFLOW = libc::EOVERFLOW, - EBADEXEC = libc::EBADEXEC, - EBADARCH = libc::EBADARCH, - ESHLIBVERS = libc::ESHLIBVERS, - EBADMACHO = libc::EBADMACHO, - ECANCELED = libc::ECANCELED, - EIDRM = libc::EIDRM, - ENOMSG = libc::ENOMSG, - EILSEQ = libc::EILSEQ, - ENOATTR = libc::ENOATTR, - EBADMSG = libc::EBADMSG, - EMULTIHOP = libc::EMULTIHOP, - ENODATA = libc::ENODATA, - ENOLINK = libc::ENOLINK, - ENOSR = libc::ENOSR, - ENOSTR = libc::ENOSTR, - EPROTO = libc::EPROTO, - ETIME = libc::ETIME, - EOPNOTSUPP = libc::EOPNOTSUPP, - ENOPOLICY = libc::ENOPOLICY, - ENOTRECOVERABLE = libc::ENOTRECOVERABLE, - EOWNERDEAD = libc::EOWNERDEAD, - EQFULL = libc::EQFULL, - } - - impl Errno { - pub const ELAST: Errno = Errno::EQFULL; - pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - pub const EDEADLOCK: Errno = Errno::EDEADLK; - } - - pub const fn from_i32(e: i32) -> Errno { - use self::Errno::*; - - match e { - libc::EPERM => EPERM, - libc::ENOENT => ENOENT, - libc::ESRCH => ESRCH, - libc::EINTR => EINTR, - libc::EIO => EIO, - libc::ENXIO => ENXIO, - libc::E2BIG => E2BIG, - libc::ENOEXEC => ENOEXEC, - libc::EBADF => EBADF, - libc::ECHILD => ECHILD, - libc::EDEADLK => EDEADLK, - libc::ENOMEM => ENOMEM, - libc::EACCES => EACCES, - libc::EFAULT => EFAULT, - libc::ENOTBLK => ENOTBLK, - libc::EBUSY => EBUSY, - libc::EEXIST => EEXIST, - libc::EXDEV => EXDEV, - libc::ENODEV => ENODEV, - libc::ENOTDIR => ENOTDIR, - libc::EISDIR => EISDIR, - libc::EINVAL => EINVAL, - libc::ENFILE => ENFILE, - libc::EMFILE => EMFILE, - libc::ENOTTY => ENOTTY, - libc::ETXTBSY => ETXTBSY, - libc::EFBIG => EFBIG, - libc::ENOSPC => ENOSPC, - libc::ESPIPE => ESPIPE, - libc::EROFS => EROFS, - libc::EMLINK => EMLINK, - libc::EPIPE => EPIPE, - libc::EDOM => EDOM, - libc::ERANGE => ERANGE, - libc::EAGAIN => EAGAIN, - libc::EINPROGRESS => EINPROGRESS, - libc::EALREADY => EALREADY, - libc::ENOTSOCK => ENOTSOCK, - libc::EDESTADDRREQ => EDESTADDRREQ, - libc::EMSGSIZE => EMSGSIZE, - libc::EPROTOTYPE => EPROTOTYPE, - libc::ENOPROTOOPT => ENOPROTOOPT, - libc::EPROTONOSUPPORT => EPROTONOSUPPORT, - libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT, - libc::ENOTSUP => ENOTSUP, - libc::EPFNOSUPPORT => EPFNOSUPPORT, - libc::EAFNOSUPPORT => EAFNOSUPPORT, - libc::EADDRINUSE => EADDRINUSE, - libc::EADDRNOTAVAIL => EADDRNOTAVAIL, - libc::ENETDOWN => ENETDOWN, - libc::ENETUNREACH => ENETUNREACH, - libc::ENETRESET => ENETRESET, - libc::ECONNABORTED => ECONNABORTED, - libc::ECONNRESET => ECONNRESET, - libc::ENOBUFS => ENOBUFS, - libc::EISCONN => EISCONN, - libc::ENOTCONN => ENOTCONN, - libc::ESHUTDOWN => ESHUTDOWN, - libc::ETOOMANYREFS => ETOOMANYREFS, - libc::ETIMEDOUT => ETIMEDOUT, - libc::ECONNREFUSED => ECONNREFUSED, - libc::ELOOP => ELOOP, - libc::ENAMETOOLONG => ENAMETOOLONG, - libc::EHOSTDOWN => EHOSTDOWN, - libc::EHOSTUNREACH => EHOSTUNREACH, - libc::ENOTEMPTY => ENOTEMPTY, - libc::EPROCLIM => EPROCLIM, - libc::EUSERS => EUSERS, - libc::EDQUOT => EDQUOT, - libc::ESTALE => ESTALE, - libc::EREMOTE => EREMOTE, - libc::EBADRPC => EBADRPC, - libc::ERPCMISMATCH => ERPCMISMATCH, - libc::EPROGUNAVAIL => EPROGUNAVAIL, - libc::EPROGMISMATCH => EPROGMISMATCH, - libc::EPROCUNAVAIL => EPROCUNAVAIL, - libc::ENOLCK => ENOLCK, - libc::ENOSYS => ENOSYS, - libc::EFTYPE => EFTYPE, - libc::EAUTH => EAUTH, - libc::ENEEDAUTH => ENEEDAUTH, - libc::EPWROFF => EPWROFF, - libc::EDEVERR => EDEVERR, - libc::EOVERFLOW => EOVERFLOW, - libc::EBADEXEC => EBADEXEC, - libc::EBADARCH => EBADARCH, - libc::ESHLIBVERS => ESHLIBVERS, - libc::EBADMACHO => EBADMACHO, - libc::ECANCELED => ECANCELED, - libc::EIDRM => EIDRM, - libc::ENOMSG => ENOMSG, - libc::EILSEQ => EILSEQ, - libc::ENOATTR => ENOATTR, - libc::EBADMSG => EBADMSG, - libc::EMULTIHOP => EMULTIHOP, - libc::ENODATA => ENODATA, - libc::ENOLINK => ENOLINK, - libc::ENOSR => ENOSR, - libc::ENOSTR => ENOSTR, - libc::EPROTO => EPROTO, - libc::ETIME => ETIME, - libc::EOPNOTSUPP => EOPNOTSUPP, - libc::ENOPOLICY => ENOPOLICY, - libc::ENOTRECOVERABLE => ENOTRECOVERABLE, - libc::EOWNERDEAD => EOWNERDEAD, - libc::EQFULL => EQFULL, - _ => UnknownErrno, - } - } -} - -#[cfg(target_os = "freebsd")] -mod consts { - #[derive(Clone, Copy, Debug, Eq, PartialEq)] - #[repr(i32)] - #[non_exhaustive] - pub enum Errno { - UnknownErrno = 0, - EPERM = libc::EPERM, - ENOENT = libc::ENOENT, - ESRCH = libc::ESRCH, - EINTR = libc::EINTR, - EIO = libc::EIO, - ENXIO = libc::ENXIO, - E2BIG = libc::E2BIG, - ENOEXEC = libc::ENOEXEC, - EBADF = libc::EBADF, - ECHILD = libc::ECHILD, - EDEADLK = libc::EDEADLK, - ENOMEM = libc::ENOMEM, - EACCES = libc::EACCES, - EFAULT = libc::EFAULT, - ENOTBLK = libc::ENOTBLK, - EBUSY = libc::EBUSY, - EEXIST = libc::EEXIST, - EXDEV = libc::EXDEV, - ENODEV = libc::ENODEV, - ENOTDIR = libc::ENOTDIR, - EISDIR = libc::EISDIR, - EINVAL = libc::EINVAL, - ENFILE = libc::ENFILE, - EMFILE = libc::EMFILE, - ENOTTY = libc::ENOTTY, - ETXTBSY = libc::ETXTBSY, - EFBIG = libc::EFBIG, - ENOSPC = libc::ENOSPC, - ESPIPE = libc::ESPIPE, - EROFS = libc::EROFS, - EMLINK = libc::EMLINK, - EPIPE = libc::EPIPE, - EDOM = libc::EDOM, - ERANGE = libc::ERANGE, - EAGAIN = libc::EAGAIN, - EINPROGRESS = libc::EINPROGRESS, - EALREADY = libc::EALREADY, - ENOTSOCK = libc::ENOTSOCK, - EDESTADDRREQ = libc::EDESTADDRREQ, - EMSGSIZE = libc::EMSGSIZE, - EPROTOTYPE = libc::EPROTOTYPE, - ENOPROTOOPT = libc::ENOPROTOOPT, - EPROTONOSUPPORT = libc::EPROTONOSUPPORT, - ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT, - ENOTSUP = libc::ENOTSUP, - EPFNOSUPPORT = libc::EPFNOSUPPORT, - EAFNOSUPPORT = libc::EAFNOSUPPORT, - EADDRINUSE = libc::EADDRINUSE, - EADDRNOTAVAIL = libc::EADDRNOTAVAIL, - ENETDOWN = libc::ENETDOWN, - ENETUNREACH = libc::ENETUNREACH, - ENETRESET = libc::ENETRESET, - ECONNABORTED = libc::ECONNABORTED, - ECONNRESET = libc::ECONNRESET, - ENOBUFS = libc::ENOBUFS, - EISCONN = libc::EISCONN, - ENOTCONN = libc::ENOTCONN, - ESHUTDOWN = libc::ESHUTDOWN, - ETOOMANYREFS = libc::ETOOMANYREFS, - ETIMEDOUT = libc::ETIMEDOUT, - ECONNREFUSED = libc::ECONNREFUSED, - ELOOP = libc::ELOOP, - ENAMETOOLONG = libc::ENAMETOOLONG, - EHOSTDOWN = libc::EHOSTDOWN, - EHOSTUNREACH = libc::EHOSTUNREACH, - ENOTEMPTY = libc::ENOTEMPTY, - EPROCLIM = libc::EPROCLIM, - EUSERS = libc::EUSERS, - EDQUOT = libc::EDQUOT, - ESTALE = libc::ESTALE, - EREMOTE = libc::EREMOTE, - EBADRPC = libc::EBADRPC, - ERPCMISMATCH = libc::ERPCMISMATCH, - EPROGUNAVAIL = libc::EPROGUNAVAIL, - EPROGMISMATCH = libc::EPROGMISMATCH, - EPROCUNAVAIL = libc::EPROCUNAVAIL, - ENOLCK = libc::ENOLCK, - ENOSYS = libc::ENOSYS, - EFTYPE = libc::EFTYPE, - EAUTH = libc::EAUTH, - ENEEDAUTH = libc::ENEEDAUTH, - EIDRM = libc::EIDRM, - ENOMSG = libc::ENOMSG, - EOVERFLOW = libc::EOVERFLOW, - ECANCELED = libc::ECANCELED, - EILSEQ = libc::EILSEQ, - ENOATTR = libc::ENOATTR, - EDOOFUS = libc::EDOOFUS, - EBADMSG = libc::EBADMSG, - EMULTIHOP = libc::EMULTIHOP, - ENOLINK = libc::ENOLINK, - EPROTO = libc::EPROTO, - ENOTCAPABLE = libc::ENOTCAPABLE, - ECAPMODE = libc::ECAPMODE, - ENOTRECOVERABLE = libc::ENOTRECOVERABLE, - EOWNERDEAD = libc::EOWNERDEAD, - } - - impl Errno { - pub const ELAST: Errno = Errno::EOWNERDEAD; - pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - pub const EDEADLOCK: Errno = Errno::EDEADLK; - pub const EOPNOTSUPP: Errno = Errno::ENOTSUP; - } - - pub const fn from_i32(e: i32) -> Errno { - use self::Errno::*; - - match e { - libc::EPERM => EPERM, - libc::ENOENT => ENOENT, - libc::ESRCH => ESRCH, - libc::EINTR => EINTR, - libc::EIO => EIO, - libc::ENXIO => ENXIO, - libc::E2BIG => E2BIG, - libc::ENOEXEC => ENOEXEC, - libc::EBADF => EBADF, - libc::ECHILD => ECHILD, - libc::EDEADLK => EDEADLK, - libc::ENOMEM => ENOMEM, - libc::EACCES => EACCES, - libc::EFAULT => EFAULT, - libc::ENOTBLK => ENOTBLK, - libc::EBUSY => EBUSY, - libc::EEXIST => EEXIST, - libc::EXDEV => EXDEV, - libc::ENODEV => ENODEV, - libc::ENOTDIR => ENOTDIR, - libc::EISDIR => EISDIR, - libc::EINVAL => EINVAL, - libc::ENFILE => ENFILE, - libc::EMFILE => EMFILE, - libc::ENOTTY => ENOTTY, - libc::ETXTBSY => ETXTBSY, - libc::EFBIG => EFBIG, - libc::ENOSPC => ENOSPC, - libc::ESPIPE => ESPIPE, - libc::EROFS => EROFS, - libc::EMLINK => EMLINK, - libc::EPIPE => EPIPE, - libc::EDOM => EDOM, - libc::ERANGE => ERANGE, - libc::EAGAIN => EAGAIN, - libc::EINPROGRESS => EINPROGRESS, - libc::EALREADY => EALREADY, - libc::ENOTSOCK => ENOTSOCK, - libc::EDESTADDRREQ => EDESTADDRREQ, - libc::EMSGSIZE => EMSGSIZE, - libc::EPROTOTYPE => EPROTOTYPE, - libc::ENOPROTOOPT => ENOPROTOOPT, - libc::EPROTONOSUPPORT => EPROTONOSUPPORT, - libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT, - libc::ENOTSUP => ENOTSUP, - libc::EPFNOSUPPORT => EPFNOSUPPORT, - libc::EAFNOSUPPORT => EAFNOSUPPORT, - libc::EADDRINUSE => EADDRINUSE, - libc::EADDRNOTAVAIL => EADDRNOTAVAIL, - libc::ENETDOWN => ENETDOWN, - libc::ENETUNREACH => ENETUNREACH, - libc::ENETRESET => ENETRESET, - libc::ECONNABORTED => ECONNABORTED, - libc::ECONNRESET => ECONNRESET, - libc::ENOBUFS => ENOBUFS, - libc::EISCONN => EISCONN, - libc::ENOTCONN => ENOTCONN, - libc::ESHUTDOWN => ESHUTDOWN, - libc::ETOOMANYREFS => ETOOMANYREFS, - libc::ETIMEDOUT => ETIMEDOUT, - libc::ECONNREFUSED => ECONNREFUSED, - libc::ELOOP => ELOOP, - libc::ENAMETOOLONG => ENAMETOOLONG, - libc::EHOSTDOWN => EHOSTDOWN, - libc::EHOSTUNREACH => EHOSTUNREACH, - libc::ENOTEMPTY => ENOTEMPTY, - libc::EPROCLIM => EPROCLIM, - libc::EUSERS => EUSERS, - libc::EDQUOT => EDQUOT, - libc::ESTALE => ESTALE, - libc::EREMOTE => EREMOTE, - libc::EBADRPC => EBADRPC, - libc::ERPCMISMATCH => ERPCMISMATCH, - libc::EPROGUNAVAIL => EPROGUNAVAIL, - libc::EPROGMISMATCH => EPROGMISMATCH, - libc::EPROCUNAVAIL => EPROCUNAVAIL, - libc::ENOLCK => ENOLCK, - libc::ENOSYS => ENOSYS, - libc::EFTYPE => EFTYPE, - libc::EAUTH => EAUTH, - libc::ENEEDAUTH => ENEEDAUTH, - libc::EIDRM => EIDRM, - libc::ENOMSG => ENOMSG, - libc::EOVERFLOW => EOVERFLOW, - libc::ECANCELED => ECANCELED, - libc::EILSEQ => EILSEQ, - libc::ENOATTR => ENOATTR, - libc::EDOOFUS => EDOOFUS, - libc::EBADMSG => EBADMSG, - libc::EMULTIHOP => EMULTIHOP, - libc::ENOLINK => ENOLINK, - libc::EPROTO => EPROTO, - libc::ENOTCAPABLE => ENOTCAPABLE, - libc::ECAPMODE => ECAPMODE, - libc::ENOTRECOVERABLE => ENOTRECOVERABLE, - libc::EOWNERDEAD => EOWNERDEAD, - _ => UnknownErrno, - } - } -} - -#[cfg(target_os = "dragonfly")] -mod consts { - #[derive(Clone, Copy, Debug, Eq, PartialEq)] - #[repr(i32)] - #[non_exhaustive] - pub enum Errno { - UnknownErrno = 0, - EPERM = libc::EPERM, - ENOENT = libc::ENOENT, - ESRCH = libc::ESRCH, - EINTR = libc::EINTR, - EIO = libc::EIO, - ENXIO = libc::ENXIO, - E2BIG = libc::E2BIG, - ENOEXEC = libc::ENOEXEC, - EBADF = libc::EBADF, - ECHILD = libc::ECHILD, - EDEADLK = libc::EDEADLK, - ENOMEM = libc::ENOMEM, - EACCES = libc::EACCES, - EFAULT = libc::EFAULT, - ENOTBLK = libc::ENOTBLK, - EBUSY = libc::EBUSY, - EEXIST = libc::EEXIST, - EXDEV = libc::EXDEV, - ENODEV = libc::ENODEV, - ENOTDIR = libc::ENOTDIR, - EISDIR = libc::EISDIR, - EINVAL = libc::EINVAL, - ENFILE = libc::ENFILE, - EMFILE = libc::EMFILE, - ENOTTY = libc::ENOTTY, - ETXTBSY = libc::ETXTBSY, - EFBIG = libc::EFBIG, - ENOSPC = libc::ENOSPC, - ESPIPE = libc::ESPIPE, - EROFS = libc::EROFS, - EMLINK = libc::EMLINK, - EPIPE = libc::EPIPE, - EDOM = libc::EDOM, - ERANGE = libc::ERANGE, - EAGAIN = libc::EAGAIN, - EINPROGRESS = libc::EINPROGRESS, - EALREADY = libc::EALREADY, - ENOTSOCK = libc::ENOTSOCK, - EDESTADDRREQ = libc::EDESTADDRREQ, - EMSGSIZE = libc::EMSGSIZE, - EPROTOTYPE = libc::EPROTOTYPE, - ENOPROTOOPT = libc::ENOPROTOOPT, - EPROTONOSUPPORT = libc::EPROTONOSUPPORT, - ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT, - ENOTSUP = libc::ENOTSUP, - EPFNOSUPPORT = libc::EPFNOSUPPORT, - EAFNOSUPPORT = libc::EAFNOSUPPORT, - EADDRINUSE = libc::EADDRINUSE, - EADDRNOTAVAIL = libc::EADDRNOTAVAIL, - ENETDOWN = libc::ENETDOWN, - ENETUNREACH = libc::ENETUNREACH, - ENETRESET = libc::ENETRESET, - ECONNABORTED = libc::ECONNABORTED, - ECONNRESET = libc::ECONNRESET, - ENOBUFS = libc::ENOBUFS, - EISCONN = libc::EISCONN, - ENOTCONN = libc::ENOTCONN, - ESHUTDOWN = libc::ESHUTDOWN, - ETOOMANYREFS = libc::ETOOMANYREFS, - ETIMEDOUT = libc::ETIMEDOUT, - ECONNREFUSED = libc::ECONNREFUSED, - ELOOP = libc::ELOOP, - ENAMETOOLONG = libc::ENAMETOOLONG, - EHOSTDOWN = libc::EHOSTDOWN, - EHOSTUNREACH = libc::EHOSTUNREACH, - ENOTEMPTY = libc::ENOTEMPTY, - EPROCLIM = libc::EPROCLIM, - EUSERS = libc::EUSERS, - EDQUOT = libc::EDQUOT, - ESTALE = libc::ESTALE, - EREMOTE = libc::EREMOTE, - EBADRPC = libc::EBADRPC, - ERPCMISMATCH = libc::ERPCMISMATCH, - EPROGUNAVAIL = libc::EPROGUNAVAIL, - EPROGMISMATCH = libc::EPROGMISMATCH, - EPROCUNAVAIL = libc::EPROCUNAVAIL, - ENOLCK = libc::ENOLCK, - ENOSYS = libc::ENOSYS, - EFTYPE = libc::EFTYPE, - EAUTH = libc::EAUTH, - ENEEDAUTH = libc::ENEEDAUTH, - EIDRM = libc::EIDRM, - ENOMSG = libc::ENOMSG, - EOVERFLOW = libc::EOVERFLOW, - ECANCELED = libc::ECANCELED, - EILSEQ = libc::EILSEQ, - ENOATTR = libc::ENOATTR, - EDOOFUS = libc::EDOOFUS, - EBADMSG = libc::EBADMSG, - EMULTIHOP = libc::EMULTIHOP, - ENOLINK = libc::ENOLINK, - EPROTO = libc::EPROTO, - ENOMEDIUM = libc::ENOMEDIUM, - ENOTRECOVERABLE = libc::ENOTRECOVERABLE, - EOWNERDEAD = libc::EOWNERDEAD, - EASYNC = libc::EASYNC, - } - - impl Errno { - pub const ELAST: Errno = Errno::EASYNC; - pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - pub const EDEADLOCK: Errno = Errno::EDEADLK; - pub const EOPNOTSUPP: Errno = Errno::ENOTSUP; - } - - pub const fn from_i32(e: i32) -> Errno { - use self::Errno::*; - - match e { - libc::EPERM => EPERM, - libc::ENOENT => ENOENT, - libc::ESRCH => ESRCH, - libc::EINTR => EINTR, - libc::EIO => EIO, - libc::ENXIO => ENXIO, - libc::E2BIG => E2BIG, - libc::ENOEXEC => ENOEXEC, - libc::EBADF => EBADF, - libc::ECHILD => ECHILD, - libc::EDEADLK => EDEADLK, - libc::ENOMEM => ENOMEM, - libc::EACCES => EACCES, - libc::EFAULT => EFAULT, - libc::ENOTBLK => ENOTBLK, - libc::EBUSY => EBUSY, - libc::EEXIST => EEXIST, - libc::EXDEV => EXDEV, - libc::ENODEV => ENODEV, - libc::ENOTDIR => ENOTDIR, - libc::EISDIR => EISDIR, - libc::EINVAL => EINVAL, - libc::ENFILE => ENFILE, - libc::EMFILE => EMFILE, - libc::ENOTTY => ENOTTY, - libc::ETXTBSY => ETXTBSY, - libc::EFBIG => EFBIG, - libc::ENOSPC => ENOSPC, - libc::ESPIPE => ESPIPE, - libc::EROFS => EROFS, - libc::EMLINK => EMLINK, - libc::EPIPE => EPIPE, - libc::EDOM => EDOM, - libc::ERANGE => ERANGE, - libc::EAGAIN => EAGAIN, - libc::EINPROGRESS => EINPROGRESS, - libc::EALREADY => EALREADY, - libc::ENOTSOCK => ENOTSOCK, - libc::EDESTADDRREQ => EDESTADDRREQ, - libc::EMSGSIZE => EMSGSIZE, - libc::EPROTOTYPE => EPROTOTYPE, - libc::ENOPROTOOPT => ENOPROTOOPT, - libc::EPROTONOSUPPORT => EPROTONOSUPPORT, - libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT, - libc::ENOTSUP => ENOTSUP, - libc::EPFNOSUPPORT => EPFNOSUPPORT, - libc::EAFNOSUPPORT => EAFNOSUPPORT, - libc::EADDRINUSE => EADDRINUSE, - libc::EADDRNOTAVAIL => EADDRNOTAVAIL, - libc::ENETDOWN => ENETDOWN, - libc::ENETUNREACH => ENETUNREACH, - libc::ENETRESET => ENETRESET, - libc::ECONNABORTED => ECONNABORTED, - libc::ECONNRESET => ECONNRESET, - libc::ENOBUFS => ENOBUFS, - libc::EISCONN => EISCONN, - libc::ENOTCONN => ENOTCONN, - libc::ESHUTDOWN => ESHUTDOWN, - libc::ETOOMANYREFS => ETOOMANYREFS, - libc::ETIMEDOUT => ETIMEDOUT, - libc::ECONNREFUSED => ECONNREFUSED, - libc::ELOOP => ELOOP, - libc::ENAMETOOLONG => ENAMETOOLONG, - libc::EHOSTDOWN => EHOSTDOWN, - libc::EHOSTUNREACH => EHOSTUNREACH, - libc::ENOTEMPTY => ENOTEMPTY, - libc::EPROCLIM => EPROCLIM, - libc::EUSERS => EUSERS, - libc::EDQUOT => EDQUOT, - libc::ESTALE => ESTALE, - libc::EREMOTE => EREMOTE, - libc::EBADRPC => EBADRPC, - libc::ERPCMISMATCH => ERPCMISMATCH, - libc::EPROGUNAVAIL => EPROGUNAVAIL, - libc::EPROGMISMATCH => EPROGMISMATCH, - libc::EPROCUNAVAIL => EPROCUNAVAIL, - libc::ENOLCK => ENOLCK, - libc::ENOSYS => ENOSYS, - libc::EFTYPE => EFTYPE, - libc::EAUTH => EAUTH, - libc::ENEEDAUTH => ENEEDAUTH, - libc::EIDRM => EIDRM, - libc::ENOMSG => ENOMSG, - libc::EOVERFLOW => EOVERFLOW, - libc::ECANCELED => ECANCELED, - libc::EILSEQ => EILSEQ, - libc::ENOATTR => ENOATTR, - libc::EDOOFUS => EDOOFUS, - libc::EBADMSG => EBADMSG, - libc::EMULTIHOP => EMULTIHOP, - libc::ENOLINK => ENOLINK, - libc::EPROTO => EPROTO, - libc::ENOMEDIUM => ENOMEDIUM, - libc::EASYNC => EASYNC, - _ => UnknownErrno, - } - } -} - -#[cfg(target_os = "openbsd")] -mod consts { - #[derive(Clone, Copy, Debug, Eq, PartialEq)] - #[repr(i32)] - #[non_exhaustive] - pub enum Errno { - UnknownErrno = 0, - EPERM = libc::EPERM, - ENOENT = libc::ENOENT, - ESRCH = libc::ESRCH, - EINTR = libc::EINTR, - EIO = libc::EIO, - ENXIO = libc::ENXIO, - E2BIG = libc::E2BIG, - ENOEXEC = libc::ENOEXEC, - EBADF = libc::EBADF, - ECHILD = libc::ECHILD, - EDEADLK = libc::EDEADLK, - ENOMEM = libc::ENOMEM, - EACCES = libc::EACCES, - EFAULT = libc::EFAULT, - ENOTBLK = libc::ENOTBLK, - EBUSY = libc::EBUSY, - EEXIST = libc::EEXIST, - EXDEV = libc::EXDEV, - ENODEV = libc::ENODEV, - ENOTDIR = libc::ENOTDIR, - EISDIR = libc::EISDIR, - EINVAL = libc::EINVAL, - ENFILE = libc::ENFILE, - EMFILE = libc::EMFILE, - ENOTTY = libc::ENOTTY, - ETXTBSY = libc::ETXTBSY, - EFBIG = libc::EFBIG, - ENOSPC = libc::ENOSPC, - ESPIPE = libc::ESPIPE, - EROFS = libc::EROFS, - EMLINK = libc::EMLINK, - EPIPE = libc::EPIPE, - EDOM = libc::EDOM, - ERANGE = libc::ERANGE, - EAGAIN = libc::EAGAIN, - EINPROGRESS = libc::EINPROGRESS, - EALREADY = libc::EALREADY, - ENOTSOCK = libc::ENOTSOCK, - EDESTADDRREQ = libc::EDESTADDRREQ, - EMSGSIZE = libc::EMSGSIZE, - EPROTOTYPE = libc::EPROTOTYPE, - ENOPROTOOPT = libc::ENOPROTOOPT, - EPROTONOSUPPORT = libc::EPROTONOSUPPORT, - ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT, - EOPNOTSUPP = libc::EOPNOTSUPP, - EPFNOSUPPORT = libc::EPFNOSUPPORT, - EAFNOSUPPORT = libc::EAFNOSUPPORT, - EADDRINUSE = libc::EADDRINUSE, - EADDRNOTAVAIL = libc::EADDRNOTAVAIL, - ENETDOWN = libc::ENETDOWN, - ENETUNREACH = libc::ENETUNREACH, - ENETRESET = libc::ENETRESET, - ECONNABORTED = libc::ECONNABORTED, - ECONNRESET = libc::ECONNRESET, - ENOBUFS = libc::ENOBUFS, - EISCONN = libc::EISCONN, - ENOTCONN = libc::ENOTCONN, - ESHUTDOWN = libc::ESHUTDOWN, - ETOOMANYREFS = libc::ETOOMANYREFS, - ETIMEDOUT = libc::ETIMEDOUT, - ECONNREFUSED = libc::ECONNREFUSED, - ELOOP = libc::ELOOP, - ENAMETOOLONG = libc::ENAMETOOLONG, - EHOSTDOWN = libc::EHOSTDOWN, - EHOSTUNREACH = libc::EHOSTUNREACH, - ENOTEMPTY = libc::ENOTEMPTY, - EPROCLIM = libc::EPROCLIM, - EUSERS = libc::EUSERS, - EDQUOT = libc::EDQUOT, - ESTALE = libc::ESTALE, - EREMOTE = libc::EREMOTE, - EBADRPC = libc::EBADRPC, - ERPCMISMATCH = libc::ERPCMISMATCH, - EPROGUNAVAIL = libc::EPROGUNAVAIL, - EPROGMISMATCH = libc::EPROGMISMATCH, - EPROCUNAVAIL = libc::EPROCUNAVAIL, - ENOLCK = libc::ENOLCK, - ENOSYS = libc::ENOSYS, - EFTYPE = libc::EFTYPE, - EAUTH = libc::EAUTH, - ENEEDAUTH = libc::ENEEDAUTH, - EIPSEC = libc::EIPSEC, - ENOATTR = libc::ENOATTR, - EILSEQ = libc::EILSEQ, - ENOMEDIUM = libc::ENOMEDIUM, - EMEDIUMTYPE = libc::EMEDIUMTYPE, - EOVERFLOW = libc::EOVERFLOW, - ECANCELED = libc::ECANCELED, - EIDRM = libc::EIDRM, - ENOMSG = libc::ENOMSG, - ENOTSUP = libc::ENOTSUP, - EBADMSG = libc::EBADMSG, - ENOTRECOVERABLE = libc::ENOTRECOVERABLE, - EOWNERDEAD = libc::EOWNERDEAD, - EPROTO = libc::EPROTO, - } - - impl Errno { - pub const ELAST: Errno = Errno::ENOTSUP; - pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - } - - pub const fn from_i32(e: i32) -> Errno { - use self::Errno::*; - - match e { - libc::EPERM => EPERM, - libc::ENOENT => ENOENT, - libc::ESRCH => ESRCH, - libc::EINTR => EINTR, - libc::EIO => EIO, - libc::ENXIO => ENXIO, - libc::E2BIG => E2BIG, - libc::ENOEXEC => ENOEXEC, - libc::EBADF => EBADF, - libc::ECHILD => ECHILD, - libc::EDEADLK => EDEADLK, - libc::ENOMEM => ENOMEM, - libc::EACCES => EACCES, - libc::EFAULT => EFAULT, - libc::ENOTBLK => ENOTBLK, - libc::EBUSY => EBUSY, - libc::EEXIST => EEXIST, - libc::EXDEV => EXDEV, - libc::ENODEV => ENODEV, - libc::ENOTDIR => ENOTDIR, - libc::EISDIR => EISDIR, - libc::EINVAL => EINVAL, - libc::ENFILE => ENFILE, - libc::EMFILE => EMFILE, - libc::ENOTTY => ENOTTY, - libc::ETXTBSY => ETXTBSY, - libc::EFBIG => EFBIG, - libc::ENOSPC => ENOSPC, - libc::ESPIPE => ESPIPE, - libc::EROFS => EROFS, - libc::EMLINK => EMLINK, - libc::EPIPE => EPIPE, - libc::EDOM => EDOM, - libc::ERANGE => ERANGE, - libc::EAGAIN => EAGAIN, - libc::EINPROGRESS => EINPROGRESS, - libc::EALREADY => EALREADY, - libc::ENOTSOCK => ENOTSOCK, - libc::EDESTADDRREQ => EDESTADDRREQ, - libc::EMSGSIZE => EMSGSIZE, - libc::EPROTOTYPE => EPROTOTYPE, - libc::ENOPROTOOPT => ENOPROTOOPT, - libc::EPROTONOSUPPORT => EPROTONOSUPPORT, - libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT, - libc::EOPNOTSUPP => EOPNOTSUPP, - libc::EPFNOSUPPORT => EPFNOSUPPORT, - libc::EAFNOSUPPORT => EAFNOSUPPORT, - libc::EADDRINUSE => EADDRINUSE, - libc::EADDRNOTAVAIL => EADDRNOTAVAIL, - libc::ENETDOWN => ENETDOWN, - libc::ENETUNREACH => ENETUNREACH, - libc::ENETRESET => ENETRESET, - libc::ECONNABORTED => ECONNABORTED, - libc::ECONNRESET => ECONNRESET, - libc::ENOBUFS => ENOBUFS, - libc::EISCONN => EISCONN, - libc::ENOTCONN => ENOTCONN, - libc::ESHUTDOWN => ESHUTDOWN, - libc::ETOOMANYREFS => ETOOMANYREFS, - libc::ETIMEDOUT => ETIMEDOUT, - libc::ECONNREFUSED => ECONNREFUSED, - libc::ELOOP => ELOOP, - libc::ENAMETOOLONG => ENAMETOOLONG, - libc::EHOSTDOWN => EHOSTDOWN, - libc::EHOSTUNREACH => EHOSTUNREACH, - libc::ENOTEMPTY => ENOTEMPTY, - libc::EPROCLIM => EPROCLIM, - libc::EUSERS => EUSERS, - libc::EDQUOT => EDQUOT, - libc::ESTALE => ESTALE, - libc::EREMOTE => EREMOTE, - libc::EBADRPC => EBADRPC, - libc::ERPCMISMATCH => ERPCMISMATCH, - libc::EPROGUNAVAIL => EPROGUNAVAIL, - libc::EPROGMISMATCH => EPROGMISMATCH, - libc::EPROCUNAVAIL => EPROCUNAVAIL, - libc::ENOLCK => ENOLCK, - libc::ENOSYS => ENOSYS, - libc::EFTYPE => EFTYPE, - libc::EAUTH => EAUTH, - libc::ENEEDAUTH => ENEEDAUTH, - libc::EIPSEC => EIPSEC, - libc::ENOATTR => ENOATTR, - libc::EILSEQ => EILSEQ, - libc::ENOMEDIUM => ENOMEDIUM, - libc::EMEDIUMTYPE => EMEDIUMTYPE, - libc::EOVERFLOW => EOVERFLOW, - libc::ECANCELED => ECANCELED, - libc::EIDRM => EIDRM, - libc::ENOMSG => ENOMSG, - libc::ENOTSUP => ENOTSUP, - libc::EBADMSG => EBADMSG, - libc::ENOTRECOVERABLE => ENOTRECOVERABLE, - libc::EOWNERDEAD => EOWNERDEAD, - libc::EPROTO => EPROTO, - _ => UnknownErrno, - } - } -} - -#[cfg(target_os = "netbsd")] -mod consts { - #[derive(Clone, Copy, Debug, Eq, PartialEq)] - #[repr(i32)] - #[non_exhaustive] - pub enum Errno { - UnknownErrno = 0, - EPERM = libc::EPERM, - ENOENT = libc::ENOENT, - ESRCH = libc::ESRCH, - EINTR = libc::EINTR, - EIO = libc::EIO, - ENXIO = libc::ENXIO, - E2BIG = libc::E2BIG, - ENOEXEC = libc::ENOEXEC, - EBADF = libc::EBADF, - ECHILD = libc::ECHILD, - EDEADLK = libc::EDEADLK, - ENOMEM = libc::ENOMEM, - EACCES = libc::EACCES, - EFAULT = libc::EFAULT, - ENOTBLK = libc::ENOTBLK, - EBUSY = libc::EBUSY, - EEXIST = libc::EEXIST, - EXDEV = libc::EXDEV, - ENODEV = libc::ENODEV, - ENOTDIR = libc::ENOTDIR, - EISDIR = libc::EISDIR, - EINVAL = libc::EINVAL, - ENFILE = libc::ENFILE, - EMFILE = libc::EMFILE, - ENOTTY = libc::ENOTTY, - ETXTBSY = libc::ETXTBSY, - EFBIG = libc::EFBIG, - ENOSPC = libc::ENOSPC, - ESPIPE = libc::ESPIPE, - EROFS = libc::EROFS, - EMLINK = libc::EMLINK, - EPIPE = libc::EPIPE, - EDOM = libc::EDOM, - ERANGE = libc::ERANGE, - EAGAIN = libc::EAGAIN, - EINPROGRESS = libc::EINPROGRESS, - EALREADY = libc::EALREADY, - ENOTSOCK = libc::ENOTSOCK, - EDESTADDRREQ = libc::EDESTADDRREQ, - EMSGSIZE = libc::EMSGSIZE, - EPROTOTYPE = libc::EPROTOTYPE, - ENOPROTOOPT = libc::ENOPROTOOPT, - EPROTONOSUPPORT = libc::EPROTONOSUPPORT, - ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT, - EOPNOTSUPP = libc::EOPNOTSUPP, - EPFNOSUPPORT = libc::EPFNOSUPPORT, - EAFNOSUPPORT = libc::EAFNOSUPPORT, - EADDRINUSE = libc::EADDRINUSE, - EADDRNOTAVAIL = libc::EADDRNOTAVAIL, - ENETDOWN = libc::ENETDOWN, - ENETUNREACH = libc::ENETUNREACH, - ENETRESET = libc::ENETRESET, - ECONNABORTED = libc::ECONNABORTED, - ECONNRESET = libc::ECONNRESET, - ENOBUFS = libc::ENOBUFS, - EISCONN = libc::EISCONN, - ENOTCONN = libc::ENOTCONN, - ESHUTDOWN = libc::ESHUTDOWN, - ETOOMANYREFS = libc::ETOOMANYREFS, - ETIMEDOUT = libc::ETIMEDOUT, - ECONNREFUSED = libc::ECONNREFUSED, - ELOOP = libc::ELOOP, - ENAMETOOLONG = libc::ENAMETOOLONG, - EHOSTDOWN = libc::EHOSTDOWN, - EHOSTUNREACH = libc::EHOSTUNREACH, - ENOTEMPTY = libc::ENOTEMPTY, - EPROCLIM = libc::EPROCLIM, - EUSERS = libc::EUSERS, - EDQUOT = libc::EDQUOT, - ESTALE = libc::ESTALE, - EREMOTE = libc::EREMOTE, - EBADRPC = libc::EBADRPC, - ERPCMISMATCH = libc::ERPCMISMATCH, - EPROGUNAVAIL = libc::EPROGUNAVAIL, - EPROGMISMATCH = libc::EPROGMISMATCH, - EPROCUNAVAIL = libc::EPROCUNAVAIL, - ENOLCK = libc::ENOLCK, - ENOSYS = libc::ENOSYS, - EFTYPE = libc::EFTYPE, - EAUTH = libc::EAUTH, - ENEEDAUTH = libc::ENEEDAUTH, - EIDRM = libc::EIDRM, - ENOMSG = libc::ENOMSG, - EOVERFLOW = libc::EOVERFLOW, - EILSEQ = libc::EILSEQ, - ENOTSUP = libc::ENOTSUP, - ECANCELED = libc::ECANCELED, - EBADMSG = libc::EBADMSG, - ENODATA = libc::ENODATA, - ENOSR = libc::ENOSR, - ENOSTR = libc::ENOSTR, - ETIME = libc::ETIME, - ENOATTR = libc::ENOATTR, - EMULTIHOP = libc::EMULTIHOP, - ENOLINK = libc::ENOLINK, - EPROTO = libc::EPROTO, - } - - impl Errno { - pub const ELAST: Errno = Errno::ENOTSUP; - pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - } - - pub const fn from_i32(e: i32) -> Errno { - use self::Errno::*; - - match e { - libc::EPERM => EPERM, - libc::ENOENT => ENOENT, - libc::ESRCH => ESRCH, - libc::EINTR => EINTR, - libc::EIO => EIO, - libc::ENXIO => ENXIO, - libc::E2BIG => E2BIG, - libc::ENOEXEC => ENOEXEC, - libc::EBADF => EBADF, - libc::ECHILD => ECHILD, - libc::EDEADLK => EDEADLK, - libc::ENOMEM => ENOMEM, - libc::EACCES => EACCES, - libc::EFAULT => EFAULT, - libc::ENOTBLK => ENOTBLK, - libc::EBUSY => EBUSY, - libc::EEXIST => EEXIST, - libc::EXDEV => EXDEV, - libc::ENODEV => ENODEV, - libc::ENOTDIR => ENOTDIR, - libc::EISDIR => EISDIR, - libc::EINVAL => EINVAL, - libc::ENFILE => ENFILE, - libc::EMFILE => EMFILE, - libc::ENOTTY => ENOTTY, - libc::ETXTBSY => ETXTBSY, - libc::EFBIG => EFBIG, - libc::ENOSPC => ENOSPC, - libc::ESPIPE => ESPIPE, - libc::EROFS => EROFS, - libc::EMLINK => EMLINK, - libc::EPIPE => EPIPE, - libc::EDOM => EDOM, - libc::ERANGE => ERANGE, - libc::EAGAIN => EAGAIN, - libc::EINPROGRESS => EINPROGRESS, - libc::EALREADY => EALREADY, - libc::ENOTSOCK => ENOTSOCK, - libc::EDESTADDRREQ => EDESTADDRREQ, - libc::EMSGSIZE => EMSGSIZE, - libc::EPROTOTYPE => EPROTOTYPE, - libc::ENOPROTOOPT => ENOPROTOOPT, - libc::EPROTONOSUPPORT => EPROTONOSUPPORT, - libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT, - libc::EOPNOTSUPP => EOPNOTSUPP, - libc::EPFNOSUPPORT => EPFNOSUPPORT, - libc::EAFNOSUPPORT => EAFNOSUPPORT, - libc::EADDRINUSE => EADDRINUSE, - libc::EADDRNOTAVAIL => EADDRNOTAVAIL, - libc::ENETDOWN => ENETDOWN, - libc::ENETUNREACH => ENETUNREACH, - libc::ENETRESET => ENETRESET, - libc::ECONNABORTED => ECONNABORTED, - libc::ECONNRESET => ECONNRESET, - libc::ENOBUFS => ENOBUFS, - libc::EISCONN => EISCONN, - libc::ENOTCONN => ENOTCONN, - libc::ESHUTDOWN => ESHUTDOWN, - libc::ETOOMANYREFS => ETOOMANYREFS, - libc::ETIMEDOUT => ETIMEDOUT, - libc::ECONNREFUSED => ECONNREFUSED, - libc::ELOOP => ELOOP, - libc::ENAMETOOLONG => ENAMETOOLONG, - libc::EHOSTDOWN => EHOSTDOWN, - libc::EHOSTUNREACH => EHOSTUNREACH, - libc::ENOTEMPTY => ENOTEMPTY, - libc::EPROCLIM => EPROCLIM, - libc::EUSERS => EUSERS, - libc::EDQUOT => EDQUOT, - libc::ESTALE => ESTALE, - libc::EREMOTE => EREMOTE, - libc::EBADRPC => EBADRPC, - libc::ERPCMISMATCH => ERPCMISMATCH, - libc::EPROGUNAVAIL => EPROGUNAVAIL, - libc::EPROGMISMATCH => EPROGMISMATCH, - libc::EPROCUNAVAIL => EPROCUNAVAIL, - libc::ENOLCK => ENOLCK, - libc::ENOSYS => ENOSYS, - libc::EFTYPE => EFTYPE, - libc::EAUTH => EAUTH, - libc::ENEEDAUTH => ENEEDAUTH, - libc::EIDRM => EIDRM, - libc::ENOMSG => ENOMSG, - libc::EOVERFLOW => EOVERFLOW, - libc::EILSEQ => EILSEQ, - libc::ENOTSUP => ENOTSUP, - libc::ECANCELED => ECANCELED, - libc::EBADMSG => EBADMSG, - libc::ENODATA => ENODATA, - libc::ENOSR => ENOSR, - libc::ENOSTR => ENOSTR, - libc::ETIME => ETIME, - libc::ENOATTR => ENOATTR, - libc::EMULTIHOP => EMULTIHOP, - libc::ENOLINK => ENOLINK, - libc::EPROTO => EPROTO, - _ => UnknownErrno, - } - } -} - -#[cfg(target_os = "redox")] -mod consts { - #[derive(Clone, Copy, Debug, Eq, PartialEq)] - #[repr(i32)] - #[non_exhaustive] - pub enum Errno { - UnknownErrno = 0, - EPERM = libc::EPERM, - ENOENT = libc::ENOENT, - ESRCH = libc::ESRCH, - EINTR = libc::EINTR, - EIO = libc::EIO, - ENXIO = libc::ENXIO, - E2BIG = libc::E2BIG, - ENOEXEC = libc::ENOEXEC, - EBADF = libc::EBADF, - ECHILD = libc::ECHILD, - EDEADLK = libc::EDEADLK, - ENOMEM = libc::ENOMEM, - EACCES = libc::EACCES, - EFAULT = libc::EFAULT, - ENOTBLK = libc::ENOTBLK, - EBUSY = libc::EBUSY, - EEXIST = libc::EEXIST, - EXDEV = libc::EXDEV, - ENODEV = libc::ENODEV, - ENOTDIR = libc::ENOTDIR, - EISDIR = libc::EISDIR, - EINVAL = libc::EINVAL, - ENFILE = libc::ENFILE, - EMFILE = libc::EMFILE, - ENOTTY = libc::ENOTTY, - ETXTBSY = libc::ETXTBSY, - EFBIG = libc::EFBIG, - ENOSPC = libc::ENOSPC, - ESPIPE = libc::ESPIPE, - EROFS = libc::EROFS, - EMLINK = libc::EMLINK, - EPIPE = libc::EPIPE, - EDOM = libc::EDOM, - ERANGE = libc::ERANGE, - EAGAIN = libc::EAGAIN, - EINPROGRESS = libc::EINPROGRESS, - EALREADY = libc::EALREADY, - ENOTSOCK = libc::ENOTSOCK, - EDESTADDRREQ = libc::EDESTADDRREQ, - EMSGSIZE = libc::EMSGSIZE, - EPROTOTYPE = libc::EPROTOTYPE, - ENOPROTOOPT = libc::ENOPROTOOPT, - EPROTONOSUPPORT = libc::EPROTONOSUPPORT, - ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT, - EOPNOTSUPP = libc::EOPNOTSUPP, - EPFNOSUPPORT = libc::EPFNOSUPPORT, - EAFNOSUPPORT = libc::EAFNOSUPPORT, - EADDRINUSE = libc::EADDRINUSE, - EADDRNOTAVAIL = libc::EADDRNOTAVAIL, - ENETDOWN = libc::ENETDOWN, - ENETUNREACH = libc::ENETUNREACH, - ENETRESET = libc::ENETRESET, - ECONNABORTED = libc::ECONNABORTED, - ECONNRESET = libc::ECONNRESET, - ENOBUFS = libc::ENOBUFS, - EISCONN = libc::EISCONN, - ENOTCONN = libc::ENOTCONN, - ESHUTDOWN = libc::ESHUTDOWN, - ETOOMANYREFS = libc::ETOOMANYREFS, - ETIMEDOUT = libc::ETIMEDOUT, - ECONNREFUSED = libc::ECONNREFUSED, - ELOOP = libc::ELOOP, - ENAMETOOLONG = libc::ENAMETOOLONG, - EHOSTDOWN = libc::EHOSTDOWN, - EHOSTUNREACH = libc::EHOSTUNREACH, - ENOTEMPTY = libc::ENOTEMPTY, - EUSERS = libc::EUSERS, - EDQUOT = libc::EDQUOT, - ESTALE = libc::ESTALE, - EREMOTE = libc::EREMOTE, - ENOLCK = libc::ENOLCK, - ENOSYS = libc::ENOSYS, - EIDRM = libc::EIDRM, - ENOMSG = libc::ENOMSG, - EOVERFLOW = libc::EOVERFLOW, - EILSEQ = libc::EILSEQ, - ECANCELED = libc::ECANCELED, - EBADMSG = libc::EBADMSG, - ENODATA = libc::ENODATA, - ENOSR = libc::ENOSR, - ENOSTR = libc::ENOSTR, - ETIME = libc::ETIME, - EMULTIHOP = libc::EMULTIHOP, - ENOLINK = libc::ENOLINK, - EPROTO = libc::EPROTO, - } - - impl Errno { - pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - } - - pub const fn from_i32(e: i32) -> Errno { - use self::Errno::*; - - match e { - libc::EPERM => EPERM, - libc::ENOENT => ENOENT, - libc::ESRCH => ESRCH, - libc::EINTR => EINTR, - libc::EIO => EIO, - libc::ENXIO => ENXIO, - libc::E2BIG => E2BIG, - libc::ENOEXEC => ENOEXEC, - libc::EBADF => EBADF, - libc::ECHILD => ECHILD, - libc::EDEADLK => EDEADLK, - libc::ENOMEM => ENOMEM, - libc::EACCES => EACCES, - libc::EFAULT => EFAULT, - libc::ENOTBLK => ENOTBLK, - libc::EBUSY => EBUSY, - libc::EEXIST => EEXIST, - libc::EXDEV => EXDEV, - libc::ENODEV => ENODEV, - libc::ENOTDIR => ENOTDIR, - libc::EISDIR => EISDIR, - libc::EINVAL => EINVAL, - libc::ENFILE => ENFILE, - libc::EMFILE => EMFILE, - libc::ENOTTY => ENOTTY, - libc::ETXTBSY => ETXTBSY, - libc::EFBIG => EFBIG, - libc::ENOSPC => ENOSPC, - libc::ESPIPE => ESPIPE, - libc::EROFS => EROFS, - libc::EMLINK => EMLINK, - libc::EPIPE => EPIPE, - libc::EDOM => EDOM, - libc::ERANGE => ERANGE, - libc::EAGAIN => EAGAIN, - libc::EINPROGRESS => EINPROGRESS, - libc::EALREADY => EALREADY, - libc::ENOTSOCK => ENOTSOCK, - libc::EDESTADDRREQ => EDESTADDRREQ, - libc::EMSGSIZE => EMSGSIZE, - libc::EPROTOTYPE => EPROTOTYPE, - libc::ENOPROTOOPT => ENOPROTOOPT, - libc::EPROTONOSUPPORT => EPROTONOSUPPORT, - libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT, - libc::EOPNOTSUPP => EOPNOTSUPP, - libc::EPFNOSUPPORT => EPFNOSUPPORT, - libc::EAFNOSUPPORT => EAFNOSUPPORT, - libc::EADDRINUSE => EADDRINUSE, - libc::EADDRNOTAVAIL => EADDRNOTAVAIL, - libc::ENETDOWN => ENETDOWN, - libc::ENETUNREACH => ENETUNREACH, - libc::ENETRESET => ENETRESET, - libc::ECONNABORTED => ECONNABORTED, - libc::ECONNRESET => ECONNRESET, - libc::ENOBUFS => ENOBUFS, - libc::EISCONN => EISCONN, - libc::ENOTCONN => ENOTCONN, - libc::ESHUTDOWN => ESHUTDOWN, - libc::ETOOMANYREFS => ETOOMANYREFS, - libc::ETIMEDOUT => ETIMEDOUT, - libc::ECONNREFUSED => ECONNREFUSED, - libc::ELOOP => ELOOP, - libc::ENAMETOOLONG => ENAMETOOLONG, - libc::EHOSTDOWN => EHOSTDOWN, - libc::EHOSTUNREACH => EHOSTUNREACH, - libc::ENOTEMPTY => ENOTEMPTY, - libc::EUSERS => EUSERS, - libc::EDQUOT => EDQUOT, - libc::ESTALE => ESTALE, - libc::EREMOTE => EREMOTE, - libc::ENOLCK => ENOLCK, - libc::ENOSYS => ENOSYS, - libc::EIDRM => EIDRM, - libc::ENOMSG => ENOMSG, - libc::EOVERFLOW => EOVERFLOW, - libc::EILSEQ => EILSEQ, - libc::ECANCELED => ECANCELED, - libc::EBADMSG => EBADMSG, - libc::ENODATA => ENODATA, - libc::ENOSR => ENOSR, - libc::ENOSTR => ENOSTR, - libc::ETIME => ETIME, - libc::EMULTIHOP => EMULTIHOP, - libc::ENOLINK => ENOLINK, - libc::EPROTO => EPROTO, - _ => UnknownErrno, - } - } -} - -#[cfg(any(target_os = "illumos", target_os = "solaris"))] -mod consts { - #[derive(Clone, Copy, Debug, Eq, PartialEq)] - #[repr(i32)] - #[non_exhaustive] - pub enum Errno { - UnknownErrno = 0, - EPERM = libc::EPERM, - ENOENT = libc::ENOENT, - ESRCH = libc::ESRCH, - EINTR = libc::EINTR, - EIO = libc::EIO, - ENXIO = libc::ENXIO, - E2BIG = libc::E2BIG, - ENOEXEC = libc::ENOEXEC, - EBADF = libc::EBADF, - ECHILD = libc::ECHILD, - EAGAIN = libc::EAGAIN, - ENOMEM = libc::ENOMEM, - EACCES = libc::EACCES, - EFAULT = libc::EFAULT, - ENOTBLK = libc::ENOTBLK, - EBUSY = libc::EBUSY, - EEXIST = libc::EEXIST, - EXDEV = libc::EXDEV, - ENODEV = libc::ENODEV, - ENOTDIR = libc::ENOTDIR, - EISDIR = libc::EISDIR, - EINVAL = libc::EINVAL, - ENFILE = libc::ENFILE, - EMFILE = libc::EMFILE, - ENOTTY = libc::ENOTTY, - ETXTBSY = libc::ETXTBSY, - EFBIG = libc::EFBIG, - ENOSPC = libc::ENOSPC, - ESPIPE = libc::ESPIPE, - EROFS = libc::EROFS, - EMLINK = libc::EMLINK, - EPIPE = libc::EPIPE, - EDOM = libc::EDOM, - ERANGE = libc::ERANGE, - ENOMSG = libc::ENOMSG, - EIDRM = libc::EIDRM, - ECHRNG = libc::ECHRNG, - EL2NSYNC = libc::EL2NSYNC, - EL3HLT = libc::EL3HLT, - EL3RST = libc::EL3RST, - ELNRNG = libc::ELNRNG, - EUNATCH = libc::EUNATCH, - ENOCSI = libc::ENOCSI, - EL2HLT = libc::EL2HLT, - EDEADLK = libc::EDEADLK, - ENOLCK = libc::ENOLCK, - ECANCELED = libc::ECANCELED, - ENOTSUP = libc::ENOTSUP, - EDQUOT = libc::EDQUOT, - EBADE = libc::EBADE, - EBADR = libc::EBADR, - EXFULL = libc::EXFULL, - ENOANO = libc::ENOANO, - EBADRQC = libc::EBADRQC, - EBADSLT = libc::EBADSLT, - EDEADLOCK = libc::EDEADLOCK, - EBFONT = libc::EBFONT, - EOWNERDEAD = libc::EOWNERDEAD, - ENOTRECOVERABLE = libc::ENOTRECOVERABLE, - ENOSTR = libc::ENOSTR, - ENODATA = libc::ENODATA, - ETIME = libc::ETIME, - ENOSR = libc::ENOSR, - ENONET = libc::ENONET, - ENOPKG = libc::ENOPKG, - EREMOTE = libc::EREMOTE, - ENOLINK = libc::ENOLINK, - EADV = libc::EADV, - ESRMNT = libc::ESRMNT, - ECOMM = libc::ECOMM, - EPROTO = libc::EPROTO, - ELOCKUNMAPPED = libc::ELOCKUNMAPPED, - ENOTACTIVE = libc::ENOTACTIVE, - EMULTIHOP = libc::EMULTIHOP, - EBADMSG = libc::EBADMSG, - ENAMETOOLONG = libc::ENAMETOOLONG, - EOVERFLOW = libc::EOVERFLOW, - ENOTUNIQ = libc::ENOTUNIQ, - EBADFD = libc::EBADFD, - EREMCHG = libc::EREMCHG, - ELIBACC = libc::ELIBACC, - ELIBBAD = libc::ELIBBAD, - ELIBSCN = libc::ELIBSCN, - ELIBMAX = libc::ELIBMAX, - ELIBEXEC = libc::ELIBEXEC, - EILSEQ = libc::EILSEQ, - ENOSYS = libc::ENOSYS, - ELOOP = libc::ELOOP, - ERESTART = libc::ERESTART, - ESTRPIPE = libc::ESTRPIPE, - ENOTEMPTY = libc::ENOTEMPTY, - EUSERS = libc::EUSERS, - ENOTSOCK = libc::ENOTSOCK, - EDESTADDRREQ = libc::EDESTADDRREQ, - EMSGSIZE = libc::EMSGSIZE, - EPROTOTYPE = libc::EPROTOTYPE, - ENOPROTOOPT = libc::ENOPROTOOPT, - EPROTONOSUPPORT = libc::EPROTONOSUPPORT, - ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT, - EOPNOTSUPP = libc::EOPNOTSUPP, - EPFNOSUPPORT = libc::EPFNOSUPPORT, - EAFNOSUPPORT = libc::EAFNOSUPPORT, - EADDRINUSE = libc::EADDRINUSE, - EADDRNOTAVAIL = libc::EADDRNOTAVAIL, - ENETDOWN = libc::ENETDOWN, - ENETUNREACH = libc::ENETUNREACH, - ENETRESET = libc::ENETRESET, - ECONNABORTED = libc::ECONNABORTED, - ECONNRESET = libc::ECONNRESET, - ENOBUFS = libc::ENOBUFS, - EISCONN = libc::EISCONN, - ENOTCONN = libc::ENOTCONN, - ESHUTDOWN = libc::ESHUTDOWN, - ETOOMANYREFS = libc::ETOOMANYREFS, - ETIMEDOUT = libc::ETIMEDOUT, - ECONNREFUSED = libc::ECONNREFUSED, - EHOSTDOWN = libc::EHOSTDOWN, - EHOSTUNREACH = libc::EHOSTUNREACH, - EALREADY = libc::EALREADY, - EINPROGRESS = libc::EINPROGRESS, - ESTALE = libc::ESTALE, - } - - impl Errno { - pub const ELAST: Errno = Errno::ESTALE; - pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - } - - pub const fn from_i32(e: i32) -> Errno { - use self::Errno::*; - - match e { - libc::EPERM => EPERM, - libc::ENOENT => ENOENT, - libc::ESRCH => ESRCH, - libc::EINTR => EINTR, - libc::EIO => EIO, - libc::ENXIO => ENXIO, - libc::E2BIG => E2BIG, - libc::ENOEXEC => ENOEXEC, - libc::EBADF => EBADF, - libc::ECHILD => ECHILD, - libc::EAGAIN => EAGAIN, - libc::ENOMEM => ENOMEM, - libc::EACCES => EACCES, - libc::EFAULT => EFAULT, - libc::ENOTBLK => ENOTBLK, - libc::EBUSY => EBUSY, - libc::EEXIST => EEXIST, - libc::EXDEV => EXDEV, - libc::ENODEV => ENODEV, - libc::ENOTDIR => ENOTDIR, - libc::EISDIR => EISDIR, - libc::EINVAL => EINVAL, - libc::ENFILE => ENFILE, - libc::EMFILE => EMFILE, - libc::ENOTTY => ENOTTY, - libc::ETXTBSY => ETXTBSY, - libc::EFBIG => EFBIG, - libc::ENOSPC => ENOSPC, - libc::ESPIPE => ESPIPE, - libc::EROFS => EROFS, - libc::EMLINK => EMLINK, - libc::EPIPE => EPIPE, - libc::EDOM => EDOM, - libc::ERANGE => ERANGE, - libc::ENOMSG => ENOMSG, - libc::EIDRM => EIDRM, - libc::ECHRNG => ECHRNG, - libc::EL2NSYNC => EL2NSYNC, - libc::EL3HLT => EL3HLT, - libc::EL3RST => EL3RST, - libc::ELNRNG => ELNRNG, - libc::EUNATCH => EUNATCH, - libc::ENOCSI => ENOCSI, - libc::EL2HLT => EL2HLT, - libc::EDEADLK => EDEADLK, - libc::ENOLCK => ENOLCK, - libc::ECANCELED => ECANCELED, - libc::ENOTSUP => ENOTSUP, - libc::EDQUOT => EDQUOT, - libc::EBADE => EBADE, - libc::EBADR => EBADR, - libc::EXFULL => EXFULL, - libc::ENOANO => ENOANO, - libc::EBADRQC => EBADRQC, - libc::EBADSLT => EBADSLT, - libc::EDEADLOCK => EDEADLOCK, - libc::EBFONT => EBFONT, - libc::EOWNERDEAD => EOWNERDEAD, - libc::ENOTRECOVERABLE => ENOTRECOVERABLE, - libc::ENOSTR => ENOSTR, - libc::ENODATA => ENODATA, - libc::ETIME => ETIME, - libc::ENOSR => ENOSR, - libc::ENONET => ENONET, - libc::ENOPKG => ENOPKG, - libc::EREMOTE => EREMOTE, - libc::ENOLINK => ENOLINK, - libc::EADV => EADV, - libc::ESRMNT => ESRMNT, - libc::ECOMM => ECOMM, - libc::EPROTO => EPROTO, - libc::ELOCKUNMAPPED => ELOCKUNMAPPED, - libc::ENOTACTIVE => ENOTACTIVE, - libc::EMULTIHOP => EMULTIHOP, - libc::EBADMSG => EBADMSG, - libc::ENAMETOOLONG => ENAMETOOLONG, - libc::EOVERFLOW => EOVERFLOW, - libc::ENOTUNIQ => ENOTUNIQ, - libc::EBADFD => EBADFD, - libc::EREMCHG => EREMCHG, - libc::ELIBACC => ELIBACC, - libc::ELIBBAD => ELIBBAD, - libc::ELIBSCN => ELIBSCN, - libc::ELIBMAX => ELIBMAX, - libc::ELIBEXEC => ELIBEXEC, - libc::EILSEQ => EILSEQ, - libc::ENOSYS => ENOSYS, - libc::ELOOP => ELOOP, - libc::ERESTART => ERESTART, - libc::ESTRPIPE => ESTRPIPE, - libc::ENOTEMPTY => ENOTEMPTY, - libc::EUSERS => EUSERS, - libc::ENOTSOCK => ENOTSOCK, - libc::EDESTADDRREQ => EDESTADDRREQ, - libc::EMSGSIZE => EMSGSIZE, - libc::EPROTOTYPE => EPROTOTYPE, - libc::ENOPROTOOPT => ENOPROTOOPT, - libc::EPROTONOSUPPORT => EPROTONOSUPPORT, - libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT, - libc::EOPNOTSUPP => EOPNOTSUPP, - libc::EPFNOSUPPORT => EPFNOSUPPORT, - libc::EAFNOSUPPORT => EAFNOSUPPORT, - libc::EADDRINUSE => EADDRINUSE, - libc::EADDRNOTAVAIL => EADDRNOTAVAIL, - libc::ENETDOWN => ENETDOWN, - libc::ENETUNREACH => ENETUNREACH, - libc::ENETRESET => ENETRESET, - libc::ECONNABORTED => ECONNABORTED, - libc::ECONNRESET => ECONNRESET, - libc::ENOBUFS => ENOBUFS, - libc::EISCONN => EISCONN, - libc::ENOTCONN => ENOTCONN, - libc::ESHUTDOWN => ESHUTDOWN, - libc::ETOOMANYREFS => ETOOMANYREFS, - libc::ETIMEDOUT => ETIMEDOUT, - libc::ECONNREFUSED => ECONNREFUSED, - libc::EHOSTDOWN => EHOSTDOWN, - libc::EHOSTUNREACH => EHOSTUNREACH, - libc::EALREADY => EALREADY, - libc::EINPROGRESS => EINPROGRESS, - libc::ESTALE => ESTALE, - _ => UnknownErrno, - } - } -} - -#[cfg(target_os = "haiku")] -mod consts { - #[derive(Clone, Copy, Debug, Eq, PartialEq)] - #[repr(i32)] - #[non_exhaustive] - pub enum Errno { - UnknownErrno = 0, - EPERM = libc::EPERM, - ENOENT = libc::ENOENT, - ESRCH = libc::ESRCH, - EINTR = libc::EINTR, - EIO = libc::EIO, - ENXIO = libc::ENXIO, - E2BIG = libc::E2BIG, - ENOEXEC = libc::ENOEXEC, - EBADF = libc::EBADF, - ECHILD = libc::ECHILD, - EDEADLK = libc::EDEADLK, - ENOMEM = libc::ENOMEM, - EACCES = libc::EACCES, - EFAULT = libc::EFAULT, - EBUSY = libc::EBUSY, - EEXIST = libc::EEXIST, - EXDEV = libc::EXDEV, - ENODEV = libc::ENODEV, - ENOTDIR = libc::ENOTDIR, - EISDIR = libc::EISDIR, - EINVAL = libc::EINVAL, - ENFILE = libc::ENFILE, - EMFILE = libc::EMFILE, - ENOTTY = libc::ENOTTY, - ETXTBSY = libc::ETXTBSY, - EFBIG = libc::EFBIG, - ENOSPC = libc::ENOSPC, - ESPIPE = libc::ESPIPE, - EROFS = libc::EROFS, - EMLINK = libc::EMLINK, - EPIPE = libc::EPIPE, - EDOM = libc::EDOM, - ERANGE = libc::ERANGE, - EAGAIN = libc::EAGAIN, - EINPROGRESS = libc::EINPROGRESS, - EALREADY = libc::EALREADY, - ENOTSOCK = libc::ENOTSOCK, - EDESTADDRREQ = libc::EDESTADDRREQ, - EMSGSIZE = libc::EMSGSIZE, - EPROTOTYPE = libc::EPROTOTYPE, - ENOPROTOOPT = libc::ENOPROTOOPT, - EPROTONOSUPPORT = libc::EPROTONOSUPPORT, - ENOTSUP = libc::ENOTSUP, - EADDRINUSE = libc::EADDRINUSE, - EADDRNOTAVAIL = libc::EADDRNOTAVAIL, - ENETDOWN = libc::ENETDOWN, - ENETUNREACH = libc::ENETUNREACH, - ENETRESET = libc::ENETRESET, - ECONNABORTED = libc::ECONNABORTED, - ECONNRESET = libc::ECONNRESET, - ENOBUFS = libc::ENOBUFS, - EISCONN = libc::EISCONN, - ENOTCONN = libc::ENOTCONN, - ESHUTDOWN = libc::ESHUTDOWN, - ETIMEDOUT = libc::ETIMEDOUT, - ECONNREFUSED = libc::ECONNREFUSED, - ELOOP = libc::ELOOP, - ENAMETOOLONG = libc::ENAMETOOLONG, - EHOSTDOWN = libc::EHOSTDOWN, - EHOSTUNREACH = libc::EHOSTUNREACH, - ENOTEMPTY = libc::ENOTEMPTY, - EDQUOT = libc::EDQUOT, - ESTALE = libc::ESTALE, - ENOLCK = libc::ENOLCK, - ENOSYS = libc::ENOSYS, - EIDRM = libc::EIDRM, - ENOMSG = libc::ENOMSG, - EOVERFLOW = libc::EOVERFLOW, - ECANCELED = libc::ECANCELED, - EILSEQ = libc::EILSEQ, - ENOATTR = libc::ENOATTR, - EBADMSG = libc::EBADMSG, - EMULTIHOP = libc::EMULTIHOP, - ENOLINK = libc::ENOLINK, - EPROTO = libc::EPROTO, - } - - impl Errno { - pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - pub const EDEADLOCK: Errno = Errno::EDEADLK; - pub const EOPNOTSUPP: Errno = Errno::ENOTSUP; - } - - pub const fn from_i32(e: i32) -> Errno { - use self::Errno::*; - - match e { - libc::EPERM => EPERM, - libc::ENOENT => ENOENT, - libc::ESRCH => ESRCH, - libc::EINTR => EINTR, - libc::EIO => EIO, - libc::ENXIO => ENXIO, - libc::E2BIG => E2BIG, - libc::ENOEXEC => ENOEXEC, - libc::EBADF => EBADF, - libc::ECHILD => ECHILD, - libc::EDEADLK => EDEADLK, - libc::ENOMEM => ENOMEM, - libc::EACCES => EACCES, - libc::EFAULT => EFAULT, - libc::EBUSY => EBUSY, - libc::EEXIST => EEXIST, - libc::EXDEV => EXDEV, - libc::ENODEV => ENODEV, - libc::ENOTDIR => ENOTDIR, - libc::EISDIR => EISDIR, - libc::EINVAL => EINVAL, - libc::ENFILE => ENFILE, - libc::EMFILE => EMFILE, - libc::ENOTTY => ENOTTY, - libc::ETXTBSY => ETXTBSY, - libc::EFBIG => EFBIG, - libc::ENOSPC => ENOSPC, - libc::ESPIPE => ESPIPE, - libc::EROFS => EROFS, - libc::EMLINK => EMLINK, - libc::EPIPE => EPIPE, - libc::EDOM => EDOM, - libc::ERANGE => ERANGE, - libc::EAGAIN => EAGAIN, - libc::EINPROGRESS => EINPROGRESS, - libc::EALREADY => EALREADY, - libc::ENOTSOCK => ENOTSOCK, - libc::EDESTADDRREQ => EDESTADDRREQ, - libc::EMSGSIZE => EMSGSIZE, - libc::EPROTOTYPE => EPROTOTYPE, - libc::ENOPROTOOPT => ENOPROTOOPT, - libc::EPROTONOSUPPORT => EPROTONOSUPPORT, - libc::ENOTSUP => ENOTSUP, - libc::EADDRINUSE => EADDRINUSE, - libc::EADDRNOTAVAIL => EADDRNOTAVAIL, - libc::ENETDOWN => ENETDOWN, - libc::ENETUNREACH => ENETUNREACH, - libc::ENETRESET => ENETRESET, - libc::ECONNABORTED => ECONNABORTED, - libc::ECONNRESET => ECONNRESET, - libc::ENOBUFS => ENOBUFS, - libc::EISCONN => EISCONN, - libc::ENOTCONN => ENOTCONN, - libc::ESHUTDOWN => ESHUTDOWN, - libc::ETIMEDOUT => ETIMEDOUT, - libc::ECONNREFUSED => ECONNREFUSED, - libc::ELOOP => ELOOP, - libc::ENAMETOOLONG => ENAMETOOLONG, - libc::EHOSTDOWN => EHOSTDOWN, - libc::EHOSTUNREACH => EHOSTUNREACH, - libc::ENOTEMPTY => ENOTEMPTY, - libc::EDQUOT => EDQUOT, - libc::ESTALE => ESTALE, - libc::ENOLCK => ENOLCK, - libc::ENOSYS => ENOSYS, - libc::EIDRM => EIDRM, - libc::ENOMSG => ENOMSG, - libc::EOVERFLOW => EOVERFLOW, - libc::ECANCELED => ECANCELED, - libc::EILSEQ => EILSEQ, - libc::ENOATTR => ENOATTR, - libc::EBADMSG => EBADMSG, - libc::EMULTIHOP => EMULTIHOP, - libc::ENOLINK => ENOLINK, - libc::EPROTO => EPROTO, - _ => UnknownErrno, - } - } -} diff --git a/vendor/nix/src/fcntl.rs b/vendor/nix/src/fcntl.rs deleted file mode 100644 index 650828345..000000000 --- a/vendor/nix/src/fcntl.rs +++ /dev/null @@ -1,882 +0,0 @@ -use crate::errno::Errno; -use libc::{self, c_char, c_int, c_uint, size_t, ssize_t}; -use std::ffi::OsString; -#[cfg(not(target_os = "redox"))] -use std::os::raw; -use std::os::unix::ffi::OsStringExt; -use std::os::unix::io::RawFd; - -#[cfg(feature = "fs")] -use crate::{sys::stat::Mode, NixPath, Result}; -#[cfg(any(target_os = "android", target_os = "linux"))] -use std::ptr; // For splice and copy_file_range - -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "wasi", - target_env = "uclibc", - target_os = "freebsd" -))] -#[cfg(feature = "fs")] -pub use self::posix_fadvise::{posix_fadvise, PosixFadviseAdvice}; - -#[cfg(not(target_os = "redox"))] -#[cfg(any(feature = "fs", feature = "process"))] -libc_bitflags! { - #[cfg_attr(docsrs, doc(cfg(any(feature = "fs", feature = "process"))))] - pub struct AtFlags: c_int { - AT_REMOVEDIR; - AT_SYMLINK_FOLLOW; - AT_SYMLINK_NOFOLLOW; - #[cfg(any(target_os = "android", target_os = "linux"))] - AT_NO_AUTOMOUNT; - #[cfg(any(target_os = "android", target_os = "linux"))] - AT_EMPTY_PATH; - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - AT_EACCESS; - } -} - -#[cfg(any(feature = "fs", feature = "term"))] -libc_bitflags!( - /// Configuration options for opened files. - #[cfg_attr(docsrs, doc(cfg(any(feature = "fs", feature = "term"))))] - pub struct OFlag: c_int { - /// Mask for the access mode of the file. - O_ACCMODE; - /// Use alternate I/O semantics. - #[cfg(target_os = "netbsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - O_ALT_IO; - /// Open the file in append-only mode. - O_APPEND; - /// Generate a signal when input or output becomes possible. - #[cfg(not(any(target_os = "illumos", target_os = "solaris", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - O_ASYNC; - /// Closes the file descriptor once an `execve` call is made. - /// - /// Also sets the file offset to the beginning of the file. - O_CLOEXEC; - /// Create the file if it does not exist. - O_CREAT; - /// Try to minimize cache effects of the I/O for this file. - #[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - O_DIRECT; - /// If the specified path isn't a directory, fail. - #[cfg(not(any(target_os = "illumos", target_os = "solaris")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - O_DIRECTORY; - /// Implicitly follow each `write()` with an `fdatasync()`. - #[cfg(any(target_os = "android", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - O_DSYNC; - /// Error out if a file was not created. - O_EXCL; - /// Open for execute only. - #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - O_EXEC; - /// Open with an exclusive file lock. - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - O_EXLOCK; - /// Same as `O_SYNC`. - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - all(target_os = "linux", not(target_env = "musl")), - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - O_FSYNC; - /// Allow files whose sizes can't be represented in an `off_t` to be opened. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - O_LARGEFILE; - /// Do not update the file last access time during `read(2)`s. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - O_NOATIME; - /// Don't attach the device as the process' controlling terminal. - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - O_NOCTTY; - /// Same as `O_NONBLOCK`. - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - O_NDELAY; - /// `open()` will fail if the given path is a symbolic link. - O_NOFOLLOW; - /// When possible, open the file in nonblocking mode. - O_NONBLOCK; - /// Don't deliver `SIGPIPE`. - #[cfg(target_os = "netbsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - O_NOSIGPIPE; - /// Obtain a file descriptor for low-level access. - /// - /// The file itself is not opened and other file operations will fail. - #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - O_PATH; - /// Only allow reading. - /// - /// This should not be combined with `O_WRONLY` or `O_RDWR`. - O_RDONLY; - /// Allow both reading and writing. - /// - /// This should not be combined with `O_WRONLY` or `O_RDONLY`. - O_RDWR; - /// Similar to `O_DSYNC` but applies to `read`s instead. - #[cfg(any(target_os = "linux", target_os = "netbsd", target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - O_RSYNC; - /// Skip search permission checks. - #[cfg(target_os = "netbsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - O_SEARCH; - /// Open with a shared file lock. - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - O_SHLOCK; - /// Implicitly follow each `write()` with an `fsync()`. - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - O_SYNC; - /// Create an unnamed temporary file. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - O_TMPFILE; - /// Truncate an existing regular file to 0 length if it allows writing. - O_TRUNC; - /// Restore default TTY attributes. - #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - O_TTY_INIT; - /// Only allow writing. - /// - /// This should not be combined with `O_RDONLY` or `O_RDWR`. - O_WRONLY; - } -); - -feature! { -#![feature = "fs"] - -// The conversion is not identical on all operating systems. -#[allow(clippy::useless_conversion)] -pub fn open<P: ?Sized + NixPath>(path: &P, oflag: OFlag, mode: Mode) -> Result<RawFd> { - let fd = path.with_nix_path(|cstr| { - unsafe { libc::open(cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint) } - })?; - - Errno::result(fd) -} - -// The conversion is not identical on all operating systems. -#[allow(clippy::useless_conversion)] -#[cfg(not(target_os = "redox"))] -pub fn openat<P: ?Sized + NixPath>( - dirfd: RawFd, - path: &P, - oflag: OFlag, - mode: Mode, -) -> Result<RawFd> { - let fd = path.with_nix_path(|cstr| { - unsafe { libc::openat(dirfd, cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint) } - })?; - Errno::result(fd) -} - -#[cfg(not(target_os = "redox"))] -pub fn renameat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>( - old_dirfd: Option<RawFd>, - old_path: &P1, - new_dirfd: Option<RawFd>, - new_path: &P2, -) -> Result<()> { - let res = old_path.with_nix_path(|old_cstr| { - new_path.with_nix_path(|new_cstr| unsafe { - libc::renameat( - at_rawfd(old_dirfd), - old_cstr.as_ptr(), - at_rawfd(new_dirfd), - new_cstr.as_ptr(), - ) - }) - })??; - Errno::result(res).map(drop) -} -} - -#[cfg(all(target_os = "linux", target_env = "gnu",))] -#[cfg(feature = "fs")] -libc_bitflags! { - #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] - pub struct RenameFlags: u32 { - RENAME_EXCHANGE; - RENAME_NOREPLACE; - RENAME_WHITEOUT; - } -} - -feature! { -#![feature = "fs"] -#[cfg(all( - target_os = "linux", - target_env = "gnu", -))] -pub fn renameat2<P1: ?Sized + NixPath, P2: ?Sized + NixPath>( - old_dirfd: Option<RawFd>, - old_path: &P1, - new_dirfd: Option<RawFd>, - new_path: &P2, - flags: RenameFlags, -) -> Result<()> { - let res = old_path.with_nix_path(|old_cstr| { - new_path.with_nix_path(|new_cstr| unsafe { - libc::renameat2( - at_rawfd(old_dirfd), - old_cstr.as_ptr(), - at_rawfd(new_dirfd), - new_cstr.as_ptr(), - flags.bits(), - ) - }) - })??; - Errno::result(res).map(drop) -} - -fn wrap_readlink_result(mut v: Vec<u8>, len: ssize_t) -> Result<OsString> { - unsafe { v.set_len(len as usize) } - v.shrink_to_fit(); - Ok(OsString::from_vec(v.to_vec())) -} - -fn readlink_maybe_at<P: ?Sized + NixPath>( - dirfd: Option<RawFd>, - path: &P, - v: &mut Vec<u8>, -) -> Result<libc::ssize_t> { - path.with_nix_path(|cstr| unsafe { - match dirfd { - #[cfg(target_os = "redox")] - Some(_) => unreachable!(), - #[cfg(not(target_os = "redox"))] - Some(dirfd) => libc::readlinkat( - dirfd, - cstr.as_ptr(), - v.as_mut_ptr() as *mut c_char, - v.capacity() as size_t, - ), - None => libc::readlink( - cstr.as_ptr(), - v.as_mut_ptr() as *mut c_char, - v.capacity() as size_t, - ), - } - }) -} - -fn inner_readlink<P: ?Sized + NixPath>(dirfd: Option<RawFd>, path: &P) -> Result<OsString> { - let mut v = Vec::with_capacity(libc::PATH_MAX as usize); - // simple case: result is strictly less than `PATH_MAX` - let res = readlink_maybe_at(dirfd, path, &mut v)?; - let len = Errno::result(res)?; - debug_assert!(len >= 0); - if (len as usize) < v.capacity() { - return wrap_readlink_result(v, res); - } - // Uh oh, the result is too long... - // Let's try to ask lstat how many bytes to allocate. - let reported_size = match dirfd { - #[cfg(target_os = "redox")] - Some(_) => unreachable!(), - #[cfg(any(target_os = "android", target_os = "linux"))] - Some(dirfd) => { - let flags = if path.is_empty() { AtFlags::AT_EMPTY_PATH } else { AtFlags::empty() }; - super::sys::stat::fstatat(dirfd, path, flags | AtFlags::AT_SYMLINK_NOFOLLOW) - }, - #[cfg(not(any(target_os = "android", target_os = "linux", target_os = "redox")))] - Some(dirfd) => super::sys::stat::fstatat(dirfd, path, AtFlags::AT_SYMLINK_NOFOLLOW), - None => super::sys::stat::lstat(path) - } - .map(|x| x.st_size) - .unwrap_or(0); - let mut try_size = if reported_size > 0 { - // Note: even if `lstat`'s apparently valid answer turns out to be - // wrong, we will still read the full symlink no matter what. - reported_size as usize + 1 - } else { - // If lstat doesn't cooperate, or reports an error, be a little less - // precise. - (libc::PATH_MAX as usize).max(128) << 1 - }; - loop { - v.reserve_exact(try_size); - let res = readlink_maybe_at(dirfd, path, &mut v)?; - let len = Errno::result(res)?; - debug_assert!(len >= 0); - if (len as usize) < v.capacity() { - break wrap_readlink_result(v, res); - } else { - // Ugh! Still not big enough! - match try_size.checked_shl(1) { - Some(next_size) => try_size = next_size, - // It's absurd that this would happen, but handle it sanely - // anyway. - None => break Err(Errno::ENAMETOOLONG), - } - } - } -} - -pub fn readlink<P: ?Sized + NixPath>(path: &P) -> Result<OsString> { - inner_readlink(None, path) -} - -#[cfg(not(target_os = "redox"))] -pub fn readlinkat<P: ?Sized + NixPath>(dirfd: RawFd, path: &P) -> Result<OsString> { - inner_readlink(Some(dirfd), path) -} - -/// Computes the raw fd consumed by a function of the form `*at`. -#[cfg(not(target_os = "redox"))] -pub(crate) fn at_rawfd(fd: Option<RawFd>) -> raw::c_int { - match fd { - None => libc::AT_FDCWD, - Some(fd) => fd, - } -} -} - -#[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] -#[cfg(feature = "fs")] -libc_bitflags!( - /// Additional flags for file sealing, which allows for limiting operations on a file. - #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] - pub struct SealFlag: c_int { - /// Prevents further calls to `fcntl()` with `F_ADD_SEALS`. - F_SEAL_SEAL; - /// The file cannot be reduced in size. - F_SEAL_SHRINK; - /// The size of the file cannot be increased. - F_SEAL_GROW; - /// The file contents cannot be modified. - F_SEAL_WRITE; - } -); - -#[cfg(feature = "fs")] -libc_bitflags!( - /// Additional configuration flags for `fcntl`'s `F_SETFD`. - #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] - pub struct FdFlag: c_int { - /// The file descriptor will automatically be closed during a successful `execve(2)`. - FD_CLOEXEC; - } -); - -feature! { -#![feature = "fs"] - -#[cfg(not(target_os = "redox"))] -#[derive(Debug, Eq, Hash, PartialEq)] -#[non_exhaustive] -pub enum FcntlArg<'a> { - F_DUPFD(RawFd), - F_DUPFD_CLOEXEC(RawFd), - F_GETFD, - F_SETFD(FdFlag), // FD_FLAGS - F_GETFL, - F_SETFL(OFlag), // O_NONBLOCK - F_SETLK(&'a libc::flock), - F_SETLKW(&'a libc::flock), - F_GETLK(&'a mut libc::flock), - #[cfg(any(target_os = "linux", target_os = "android"))] - F_OFD_SETLK(&'a libc::flock), - #[cfg(any(target_os = "linux", target_os = "android"))] - F_OFD_SETLKW(&'a libc::flock), - #[cfg(any(target_os = "linux", target_os = "android"))] - F_OFD_GETLK(&'a mut libc::flock), - #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] - F_ADD_SEALS(SealFlag), - #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] - F_GET_SEALS, - #[cfg(any(target_os = "macos", target_os = "ios"))] - F_FULLFSYNC, - #[cfg(any(target_os = "linux", target_os = "android"))] - F_GETPIPE_SZ, - #[cfg(any(target_os = "linux", target_os = "android"))] - F_SETPIPE_SZ(c_int), - // TODO: Rest of flags -} - -#[cfg(target_os = "redox")] -#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)] -#[non_exhaustive] -pub enum FcntlArg { - F_DUPFD(RawFd), - F_DUPFD_CLOEXEC(RawFd), - F_GETFD, - F_SETFD(FdFlag), // FD_FLAGS - F_GETFL, - F_SETFL(OFlag), // O_NONBLOCK -} -pub use self::FcntlArg::*; - -// TODO: Figure out how to handle value fcntl returns -pub fn fcntl(fd: RawFd, arg: FcntlArg) -> Result<c_int> { - let res = unsafe { - match arg { - F_DUPFD(rawfd) => libc::fcntl(fd, libc::F_DUPFD, rawfd), - F_DUPFD_CLOEXEC(rawfd) => libc::fcntl(fd, libc::F_DUPFD_CLOEXEC, rawfd), - F_GETFD => libc::fcntl(fd, libc::F_GETFD), - F_SETFD(flag) => libc::fcntl(fd, libc::F_SETFD, flag.bits()), - F_GETFL => libc::fcntl(fd, libc::F_GETFL), - F_SETFL(flag) => libc::fcntl(fd, libc::F_SETFL, flag.bits()), - #[cfg(not(target_os = "redox"))] - F_SETLK(flock) => libc::fcntl(fd, libc::F_SETLK, flock), - #[cfg(not(target_os = "redox"))] - F_SETLKW(flock) => libc::fcntl(fd, libc::F_SETLKW, flock), - #[cfg(not(target_os = "redox"))] - F_GETLK(flock) => libc::fcntl(fd, libc::F_GETLK, flock), - #[cfg(any(target_os = "android", target_os = "linux"))] - F_OFD_SETLK(flock) => libc::fcntl(fd, libc::F_OFD_SETLK, flock), - #[cfg(any(target_os = "android", target_os = "linux"))] - F_OFD_SETLKW(flock) => libc::fcntl(fd, libc::F_OFD_SETLKW, flock), - #[cfg(any(target_os = "android", target_os = "linux"))] - F_OFD_GETLK(flock) => libc::fcntl(fd, libc::F_OFD_GETLK, flock), - #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] - F_ADD_SEALS(flag) => libc::fcntl(fd, libc::F_ADD_SEALS, flag.bits()), - #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] - F_GET_SEALS => libc::fcntl(fd, libc::F_GET_SEALS), - #[cfg(any(target_os = "macos", target_os = "ios"))] - F_FULLFSYNC => libc::fcntl(fd, libc::F_FULLFSYNC), - #[cfg(any(target_os = "linux", target_os = "android"))] - F_GETPIPE_SZ => libc::fcntl(fd, libc::F_GETPIPE_SZ), - #[cfg(any(target_os = "linux", target_os = "android"))] - F_SETPIPE_SZ(size) => libc::fcntl(fd, libc::F_SETPIPE_SZ, size), - } - }; - - Errno::result(res) -} - -// TODO: convert to libc_enum -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -#[non_exhaustive] -pub enum FlockArg { - LockShared, - LockExclusive, - Unlock, - LockSharedNonblock, - LockExclusiveNonblock, - UnlockNonblock, -} - -#[cfg(not(target_os = "redox"))] -pub fn flock(fd: RawFd, arg: FlockArg) -> Result<()> { - use self::FlockArg::*; - - let res = unsafe { - match arg { - LockShared => libc::flock(fd, libc::LOCK_SH), - LockExclusive => libc::flock(fd, libc::LOCK_EX), - Unlock => libc::flock(fd, libc::LOCK_UN), - LockSharedNonblock => libc::flock(fd, libc::LOCK_SH | libc::LOCK_NB), - LockExclusiveNonblock => libc::flock(fd, libc::LOCK_EX | libc::LOCK_NB), - UnlockNonblock => libc::flock(fd, libc::LOCK_UN | libc::LOCK_NB), - } - }; - - Errno::result(res).map(drop) -} -} - -#[cfg(any(target_os = "android", target_os = "linux"))] -#[cfg(feature = "zerocopy")] -libc_bitflags! { - /// Additional flags to `splice` and friends. - #[cfg_attr(docsrs, doc(cfg(feature = "zerocopy")))] - pub struct SpliceFFlags: c_uint { - /// Request that pages be moved instead of copied. - /// - /// Not applicable to `vmsplice`. - SPLICE_F_MOVE; - /// Do not block on I/O. - SPLICE_F_NONBLOCK; - /// Hint that more data will be coming in a subsequent splice. - /// - /// Not applicable to `vmsplice`. - SPLICE_F_MORE; - /// Gift the user pages to the kernel. - /// - /// Not applicable to `splice`. - SPLICE_F_GIFT; - } -} - -feature! { -#![feature = "zerocopy"] - -/// Copy a range of data from one file to another -/// -/// The `copy_file_range` system call performs an in-kernel copy between -/// file descriptors `fd_in` and `fd_out` without the additional cost of -/// transferring data from the kernel to user space and then back into the -/// kernel. It copies up to `len` bytes of data from file descriptor `fd_in` to -/// file descriptor `fd_out`, overwriting any data that exists within the -/// requested range of the target file. -/// -/// If the `off_in` and/or `off_out` arguments are used, the values -/// will be mutated to reflect the new position within the file after -/// copying. If they are not used, the relevant filedescriptors will be seeked -/// to the new position. -/// -/// On successful completion the number of bytes actually copied will be -/// returned. -#[cfg(any(target_os = "android", target_os = "linux"))] -pub fn copy_file_range( - fd_in: RawFd, - off_in: Option<&mut libc::loff_t>, - fd_out: RawFd, - off_out: Option<&mut libc::loff_t>, - len: usize, -) -> Result<usize> { - let off_in = off_in - .map(|offset| offset as *mut libc::loff_t) - .unwrap_or(ptr::null_mut()); - let off_out = off_out - .map(|offset| offset as *mut libc::loff_t) - .unwrap_or(ptr::null_mut()); - - let ret = unsafe { - libc::syscall( - libc::SYS_copy_file_range, - fd_in, - off_in, - fd_out, - off_out, - len, - 0, - ) - }; - Errno::result(ret).map(|r| r as usize) -} - -#[cfg(any(target_os = "linux", target_os = "android"))] -pub fn splice( - fd_in: RawFd, - off_in: Option<&mut libc::loff_t>, - fd_out: RawFd, - off_out: Option<&mut libc::loff_t>, - len: usize, - flags: SpliceFFlags, -) -> Result<usize> { - let off_in = off_in - .map(|offset| offset as *mut libc::loff_t) - .unwrap_or(ptr::null_mut()); - let off_out = off_out - .map(|offset| offset as *mut libc::loff_t) - .unwrap_or(ptr::null_mut()); - - let ret = unsafe { libc::splice(fd_in, off_in, fd_out, off_out, len, flags.bits()) }; - Errno::result(ret).map(|r| r as usize) -} - -#[cfg(any(target_os = "linux", target_os = "android"))] -pub fn tee(fd_in: RawFd, fd_out: RawFd, len: usize, flags: SpliceFFlags) -> Result<usize> { - let ret = unsafe { libc::tee(fd_in, fd_out, len, flags.bits()) }; - Errno::result(ret).map(|r| r as usize) -} - -#[cfg(any(target_os = "linux", target_os = "android"))] -pub fn vmsplice( - fd: RawFd, - iov: &[std::io::IoSlice<'_>], - flags: SpliceFFlags - ) -> Result<usize> -{ - let ret = unsafe { - libc::vmsplice( - fd, - iov.as_ptr() as *const libc::iovec, - iov.len(), - flags.bits(), - ) - }; - Errno::result(ret).map(|r| r as usize) -} -} - -#[cfg(any(target_os = "linux"))] -#[cfg(feature = "fs")] -libc_bitflags!( - /// Mode argument flags for fallocate determining operation performed on a given range. - #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] - pub struct FallocateFlags: c_int { - /// File size is not changed. - /// - /// offset + len can be greater than file size. - FALLOC_FL_KEEP_SIZE; - /// Deallocates space by creating a hole. - /// - /// Must be ORed with FALLOC_FL_KEEP_SIZE. Byte range starts at offset and continues for len bytes. - FALLOC_FL_PUNCH_HOLE; - /// Removes byte range from a file without leaving a hole. - /// - /// Byte range to collapse starts at offset and continues for len bytes. - FALLOC_FL_COLLAPSE_RANGE; - /// Zeroes space in specified byte range. - /// - /// Byte range starts at offset and continues for len bytes. - FALLOC_FL_ZERO_RANGE; - /// Increases file space by inserting a hole within the file size. - /// - /// Does not overwrite existing data. Hole starts at offset and continues for len bytes. - FALLOC_FL_INSERT_RANGE; - /// Shared file data extants are made private to the file. - /// - /// Gaurantees that a subsequent write will not fail due to lack of space. - FALLOC_FL_UNSHARE_RANGE; - } -); - -feature! { -#![feature = "fs"] - -/// Manipulates file space. -/// -/// Allows the caller to directly manipulate the allocated disk space for the -/// file referred to by fd. -#[cfg(any(target_os = "linux"))] -#[cfg(feature = "fs")] -pub fn fallocate( - fd: RawFd, - mode: FallocateFlags, - offset: libc::off_t, - len: libc::off_t, -) -> Result<()> { - let res = unsafe { libc::fallocate(fd, mode.bits(), offset, len) }; - Errno::result(res).map(drop) -} - -/// Argument to [`fspacectl`] describing the range to zero. The first member is -/// the file offset, and the second is the length of the region. -#[cfg(any(target_os = "freebsd"))] -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct SpacectlRange(pub libc::off_t, pub libc::off_t); - -#[cfg(any(target_os = "freebsd"))] -impl SpacectlRange { - #[inline] - pub fn is_empty(&self) -> bool { - self.1 == 0 - } - - #[inline] - pub fn len(&self) -> libc::off_t { - self.1 - } - - #[inline] - pub fn offset(&self) -> libc::off_t { - self.0 - } -} - -/// Punch holes in a file. -/// -/// `fspacectl` instructs the file system to deallocate a portion of a file. -/// After a successful operation, this region of the file will return all zeroes -/// if read. If the file system supports deallocation, then it may free the -/// underlying storage, too. -/// -/// # Arguments -/// -/// - `fd` - File to operate on -/// - `range.0` - File offset at which to begin deallocation -/// - `range.1` - Length of the region to deallocate -/// -/// # Returns -/// -/// The operation may deallocate less than the entire requested region. On -/// success, it returns the region that still remains to be deallocated. The -/// caller should loop until the returned region is empty. -/// -/// # Example -/// -#[cfg_attr(fbsd14, doc = " ```")] -#[cfg_attr(not(fbsd14), doc = " ```no_run")] -/// # use std::io::Write; -/// # use std::os::unix::fs::FileExt; -/// # use std::os::unix::io::AsRawFd; -/// # use nix::fcntl::*; -/// # use tempfile::tempfile; -/// const INITIAL: &[u8] = b"0123456789abcdef"; -/// let mut f = tempfile().unwrap(); -/// f.write_all(INITIAL).unwrap(); -/// let mut range = SpacectlRange(3, 6); -/// while (!range.is_empty()) { -/// range = fspacectl(f.as_raw_fd(), range).unwrap(); -/// } -/// let mut buf = vec![0; INITIAL.len()]; -/// f.read_exact_at(&mut buf, 0).unwrap(); -/// assert_eq!(buf, b"012\0\0\0\0\0\09abcdef"); -/// ``` -#[cfg(target_os = "freebsd")] -pub fn fspacectl(fd: RawFd, range: SpacectlRange) -> Result<SpacectlRange> { - let mut rqsr = libc::spacectl_range{r_offset: range.0, r_len: range.1}; - let res = unsafe { libc::fspacectl( - fd, - libc::SPACECTL_DEALLOC, // Only one command is supported ATM - &rqsr, - 0, // No flags are currently supported - &mut rqsr - )}; - Errno::result(res).map(|_| SpacectlRange(rqsr.r_offset, rqsr.r_len)) -} - -/// Like [`fspacectl`], but will never return incomplete. -/// -/// # Arguments -/// -/// - `fd` - File to operate on -/// - `offset` - File offset at which to begin deallocation -/// - `len` - Length of the region to deallocate -/// -/// # Returns -/// -/// Returns `()` on success. On failure, the region may or may not be partially -/// deallocated. -/// -/// # Example -/// -#[cfg_attr(fbsd14, doc = " ```")] -#[cfg_attr(not(fbsd14), doc = " ```no_run")] -/// # use std::io::Write; -/// # use std::os::unix::fs::FileExt; -/// # use std::os::unix::io::AsRawFd; -/// # use nix::fcntl::*; -/// # use tempfile::tempfile; -/// const INITIAL: &[u8] = b"0123456789abcdef"; -/// let mut f = tempfile().unwrap(); -/// f.write_all(INITIAL).unwrap(); -/// fspacectl_all(f.as_raw_fd(), 3, 6).unwrap(); -/// let mut buf = vec![0; INITIAL.len()]; -/// f.read_exact_at(&mut buf, 0).unwrap(); -/// assert_eq!(buf, b"012\0\0\0\0\0\09abcdef"); -/// ``` -#[cfg(target_os = "freebsd")] -pub fn fspacectl_all(fd: RawFd, offset: libc::off_t, len: libc::off_t) - -> Result<()> -{ - let mut rqsr = libc::spacectl_range{r_offset: offset, r_len: len}; - while rqsr.r_len > 0 { - let res = unsafe { libc::fspacectl( - fd, - libc::SPACECTL_DEALLOC, // Only one command is supported ATM - &rqsr, - 0, // No flags are currently supported - &mut rqsr - )}; - Errno::result(res)?; - } - Ok(()) -} - -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "wasi", - target_env = "uclibc", - target_os = "freebsd" -))] -mod posix_fadvise { - use crate::errno::Errno; - use std::os::unix::io::RawFd; - use crate::Result; - - #[cfg(feature = "fs")] - libc_enum! { - #[repr(i32)] - #[non_exhaustive] - #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] - pub enum PosixFadviseAdvice { - POSIX_FADV_NORMAL, - POSIX_FADV_SEQUENTIAL, - POSIX_FADV_RANDOM, - POSIX_FADV_NOREUSE, - POSIX_FADV_WILLNEED, - POSIX_FADV_DONTNEED, - } - } - - feature! { - #![feature = "fs"] - pub fn posix_fadvise( - fd: RawFd, - offset: libc::off_t, - len: libc::off_t, - advice: PosixFadviseAdvice, - ) -> Result<()> { - let res = unsafe { libc::posix_fadvise(fd, offset, len, advice as libc::c_int) }; - - if res == 0 { - Ok(()) - } else { - Err(Errno::from_i32(res)) - } - } - } -} - -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "wasi", - target_os = "freebsd" -))] -pub fn posix_fallocate(fd: RawFd, offset: libc::off_t, len: libc::off_t) -> Result<()> { - let res = unsafe { libc::posix_fallocate(fd, offset, len) }; - match Errno::result(res) { - Err(err) => Err(err), - Ok(0) => Ok(()), - Ok(errno) => Err(Errno::from_i32(errno)), - } -} -} diff --git a/vendor/nix/src/features.rs b/vendor/nix/src/features.rs deleted file mode 100644 index 39d17604e..000000000 --- a/vendor/nix/src/features.rs +++ /dev/null @@ -1,126 +0,0 @@ -//! Feature tests for OS functionality -pub use self::os::*; - -#[cfg(any(target_os = "linux", target_os = "android"))] -mod os { - use crate::sys::utsname::uname; - use crate::Result; - use std::os::unix::ffi::OsStrExt; - - // Features: - // * atomic cloexec on socket: 2.6.27 - // * pipe2: 2.6.27 - // * accept4: 2.6.28 - - static VERS_UNKNOWN: usize = 1; - static VERS_2_6_18: usize = 2; - static VERS_2_6_27: usize = 3; - static VERS_2_6_28: usize = 4; - static VERS_3: usize = 5; - - #[inline] - fn digit(dst: &mut usize, b: u8) { - *dst *= 10; - *dst += (b - b'0') as usize; - } - - fn parse_kernel_version() -> Result<usize> { - let u = uname()?; - - let mut curr: usize = 0; - let mut major: usize = 0; - let mut minor: usize = 0; - let mut patch: usize = 0; - - for &b in u.release().as_bytes() { - if curr >= 3 { - break; - } - - match b { - b'.' | b'-' => { - curr += 1; - } - b'0'..=b'9' => match curr { - 0 => digit(&mut major, b), - 1 => digit(&mut minor, b), - _ => digit(&mut patch, b), - }, - _ => break, - } - } - - Ok(if major >= 3 { - VERS_3 - } else if major >= 2 { - if minor >= 7 { - VERS_UNKNOWN - } else if minor >= 6 { - if patch >= 28 { - VERS_2_6_28 - } else if patch >= 27 { - VERS_2_6_27 - } else { - VERS_2_6_18 - } - } else { - VERS_UNKNOWN - } - } else { - VERS_UNKNOWN - }) - } - - fn kernel_version() -> Result<usize> { - static mut KERNEL_VERS: usize = 0; - - unsafe { - if KERNEL_VERS == 0 { - KERNEL_VERS = parse_kernel_version()?; - } - - Ok(KERNEL_VERS) - } - } - - /// Check if the OS supports atomic close-on-exec for sockets - pub fn socket_atomic_cloexec() -> bool { - kernel_version() - .map(|version| version >= VERS_2_6_27) - .unwrap_or(false) - } - - #[test] - pub fn test_parsing_kernel_version() { - assert!(kernel_version().unwrap() > 0); - } -} - -#[cfg(any( - target_os = "dragonfly", // Since ??? - target_os = "freebsd", // Since 10.0 - target_os = "illumos", // Since ??? - target_os = "netbsd", // Since 6.0 - target_os = "openbsd", // Since 5.7 - target_os = "redox", // Since 1-july-2020 -))] -mod os { - /// Check if the OS supports atomic close-on-exec for sockets - pub const fn socket_atomic_cloexec() -> bool { - true - } -} - -#[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "fuchsia", - target_os = "haiku", - target_os = "solaris" -))] -mod os { - /// Check if the OS supports atomic close-on-exec for sockets - pub const fn socket_atomic_cloexec() -> bool { - false - } -} diff --git a/vendor/nix/src/ifaddrs.rs b/vendor/nix/src/ifaddrs.rs deleted file mode 100644 index 70b50b01e..000000000 --- a/vendor/nix/src/ifaddrs.rs +++ /dev/null @@ -1,213 +0,0 @@ -//! Query network interface addresses -//! -//! Uses the Linux and/or BSD specific function `getifaddrs` to query the list -//! of interfaces and their associated addresses. - -use cfg_if::cfg_if; -#[cfg(any(target_os = "ios", target_os = "macos"))] -use std::convert::TryFrom; -use std::ffi; -use std::iter::Iterator; -use std::mem; -use std::option::Option; - -use crate::net::if_::*; -use crate::sys::socket::{SockaddrLike, SockaddrStorage}; -use crate::{Errno, Result}; - -/// Describes a single address for an interface as returned by `getifaddrs`. -#[derive(Clone, Debug, Eq, Hash, PartialEq)] -pub struct InterfaceAddress { - /// Name of the network interface - pub interface_name: String, - /// Flags as from `SIOCGIFFLAGS` ioctl - pub flags: InterfaceFlags, - /// Network address of this interface - pub address: Option<SockaddrStorage>, - /// Netmask of this interface - pub netmask: Option<SockaddrStorage>, - /// Broadcast address of this interface, if applicable - pub broadcast: Option<SockaddrStorage>, - /// Point-to-point destination address - pub destination: Option<SockaddrStorage>, -} - -cfg_if! { - if #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux"))] { - fn get_ifu_from_sockaddr(info: &libc::ifaddrs) -> *const libc::sockaddr { - info.ifa_ifu - } - } else { - fn get_ifu_from_sockaddr(info: &libc::ifaddrs) -> *const libc::sockaddr { - info.ifa_dstaddr - } - } -} - -/// Workaround a bug in XNU where netmasks will always have the wrong size in -/// the sa_len field due to the kernel ignoring trailing zeroes in the structure -/// when setting the field. See https://github.com/nix-rust/nix/issues/1709#issuecomment-1199304470 -/// -/// To fix this, we stack-allocate a new sockaddr_storage, zero it out, and -/// memcpy sa_len of the netmask to that new storage. Finally, we reset the -/// ss_len field to sizeof(sockaddr_storage). This is supposedly valid as all -/// members of the sockaddr_storage are "ok" with being zeroed out (there are -/// no pointers). -#[cfg(any(target_os = "ios", target_os = "macos"))] -unsafe fn workaround_xnu_bug(info: &libc::ifaddrs) -> Option<SockaddrStorage> { - let src_sock = info.ifa_netmask; - if src_sock.is_null() { - return None; - } - - let mut dst_sock = mem::MaybeUninit::<libc::sockaddr_storage>::zeroed(); - - // memcpy only sa_len bytes, assume the rest is zero - std::ptr::copy_nonoverlapping( - src_sock as *const u8, - dst_sock.as_mut_ptr() as *mut u8, - (*src_sock).sa_len.into(), - ); - - // Initialize ss_len to sizeof(libc::sockaddr_storage). - (*dst_sock.as_mut_ptr()).ss_len = - u8::try_from(mem::size_of::<libc::sockaddr_storage>()).unwrap(); - let dst_sock = dst_sock.assume_init(); - - let dst_sock_ptr = - &dst_sock as *const libc::sockaddr_storage as *const libc::sockaddr; - - SockaddrStorage::from_raw(dst_sock_ptr, None) -} - -impl InterfaceAddress { - /// Create an `InterfaceAddress` from the libc struct. - fn from_libc_ifaddrs(info: &libc::ifaddrs) -> InterfaceAddress { - let ifname = unsafe { ffi::CStr::from_ptr(info.ifa_name) }; - let address = unsafe { SockaddrStorage::from_raw(info.ifa_addr, None) }; - #[cfg(any(target_os = "ios", target_os = "macos"))] - let netmask = unsafe { workaround_xnu_bug(info) }; - #[cfg(not(any(target_os = "ios", target_os = "macos")))] - let netmask = - unsafe { SockaddrStorage::from_raw(info.ifa_netmask, None) }; - let mut addr = InterfaceAddress { - interface_name: ifname.to_string_lossy().to_string(), - flags: InterfaceFlags::from_bits_truncate(info.ifa_flags as i32), - address, - netmask, - broadcast: None, - destination: None, - }; - - let ifu = get_ifu_from_sockaddr(info); - if addr.flags.contains(InterfaceFlags::IFF_POINTOPOINT) { - addr.destination = unsafe { SockaddrStorage::from_raw(ifu, None) }; - } else if addr.flags.contains(InterfaceFlags::IFF_BROADCAST) { - addr.broadcast = unsafe { SockaddrStorage::from_raw(ifu, None) }; - } - - addr - } -} - -/// Holds the results of `getifaddrs`. -/// -/// Use the function `getifaddrs` to create this Iterator. Note that the -/// actual list of interfaces can be iterated once and will be freed as -/// soon as the Iterator goes out of scope. -#[derive(Debug, Eq, Hash, PartialEq)] -pub struct InterfaceAddressIterator { - base: *mut libc::ifaddrs, - next: *mut libc::ifaddrs, -} - -impl Drop for InterfaceAddressIterator { - fn drop(&mut self) { - unsafe { libc::freeifaddrs(self.base) }; - } -} - -impl Iterator for InterfaceAddressIterator { - type Item = InterfaceAddress; - fn next(&mut self) -> Option<<Self as Iterator>::Item> { - match unsafe { self.next.as_ref() } { - Some(ifaddr) => { - self.next = ifaddr.ifa_next; - Some(InterfaceAddress::from_libc_ifaddrs(ifaddr)) - } - None => None, - } - } -} - -/// Get interface addresses using libc's `getifaddrs` -/// -/// Note that the underlying implementation differs between OSes. Only the -/// most common address families are supported by the nix crate (due to -/// lack of time and complexity of testing). The address family is encoded -/// in the specific variant of `SockaddrStorage` returned for the fields -/// `address`, `netmask`, `broadcast`, and `destination`. For any entry not -/// supported, the returned list will contain a `None` entry. -/// -/// # Example -/// ``` -/// let addrs = nix::ifaddrs::getifaddrs().unwrap(); -/// for ifaddr in addrs { -/// match ifaddr.address { -/// Some(address) => { -/// println!("interface {} address {}", -/// ifaddr.interface_name, address); -/// }, -/// None => { -/// println!("interface {} with unsupported address family", -/// ifaddr.interface_name); -/// } -/// } -/// } -/// ``` -pub fn getifaddrs() -> Result<InterfaceAddressIterator> { - let mut addrs = mem::MaybeUninit::<*mut libc::ifaddrs>::uninit(); - unsafe { - Errno::result(libc::getifaddrs(addrs.as_mut_ptr())).map(|_| { - InterfaceAddressIterator { - base: addrs.assume_init(), - next: addrs.assume_init(), - } - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - // Only checks if `getifaddrs` can be invoked without panicking. - #[test] - fn test_getifaddrs() { - let _ = getifaddrs(); - } - - // Ensures getting the netmask works, and in particular that - // `workaround_xnu_bug` works properly. - #[test] - fn test_getifaddrs_netmask_correct() { - let addrs = getifaddrs().unwrap(); - for iface in addrs { - let sock = if let Some(sock) = iface.netmask { - sock - } else { - continue; - }; - if sock.family() == Some(crate::sys::socket::AddressFamily::Inet) { - let _ = sock.as_sockaddr_in().unwrap(); - return; - } else if sock.family() - == Some(crate::sys::socket::AddressFamily::Inet6) - { - let _ = sock.as_sockaddr_in6().unwrap(); - return; - } - } - panic!("No address?"); - } -} diff --git a/vendor/nix/src/kmod.rs b/vendor/nix/src/kmod.rs deleted file mode 100644 index 1fa6c170d..000000000 --- a/vendor/nix/src/kmod.rs +++ /dev/null @@ -1,128 +0,0 @@ -//! Load and unload kernel modules. -//! -//! For more details see - -use std::ffi::CStr; -use std::os::unix::io::AsRawFd; - -use crate::errno::Errno; -use crate::Result; - -/// Loads a kernel module from a buffer. -/// -/// It loads an ELF image into kernel space, -/// performs any necessary symbol relocations, -/// initializes module parameters to values provided by the caller, -/// and then runs the module's init function. -/// -/// This function requires `CAP_SYS_MODULE` privilege. -/// -/// The `module_image` argument points to a buffer containing the binary image -/// to be loaded. The buffer should contain a valid ELF image -/// built for the running kernel. -/// -/// The `param_values` argument is a string containing space-delimited specifications -/// of the values for module parameters. -/// Each of the parameter specifications has the form: -/// -/// `name[=value[,value...]]` -/// -/// # Example -/// -/// ```no_run -/// use std::fs::File; -/// use std::io::Read; -/// use std::ffi::CString; -/// use nix::kmod::init_module; -/// -/// let mut f = File::open("mykernel.ko").unwrap(); -/// let mut contents: Vec<u8> = Vec::new(); -/// f.read_to_end(&mut contents).unwrap(); -/// init_module(&mut contents, &CString::new("who=Rust when=Now,12").unwrap()).unwrap(); -/// ``` -/// -/// See [`man init_module(2)`](https://man7.org/linux/man-pages/man2/init_module.2.html) for more information. -pub fn init_module(module_image: &[u8], param_values: &CStr) -> Result<()> { - let res = unsafe { - libc::syscall( - libc::SYS_init_module, - module_image.as_ptr(), - module_image.len(), - param_values.as_ptr(), - ) - }; - - Errno::result(res).map(drop) -} - -libc_bitflags!( - /// Flags used by the `finit_module` function. - pub struct ModuleInitFlags: libc::c_uint { - /// Ignore symbol version hashes. - MODULE_INIT_IGNORE_MODVERSIONS; - /// Ignore kernel version magic. - MODULE_INIT_IGNORE_VERMAGIC; - } -); - -/// Loads a kernel module from a given file descriptor. -/// -/// # Example -/// -/// ```no_run -/// use std::fs::File; -/// use std::ffi::CString; -/// use nix::kmod::{finit_module, ModuleInitFlags}; -/// -/// let f = File::open("mymod.ko").unwrap(); -/// finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty()).unwrap(); -/// ``` -/// -/// See [`man init_module(2)`](https://man7.org/linux/man-pages/man2/init_module.2.html) for more information. -pub fn finit_module<T: AsRawFd>( - fd: &T, - param_values: &CStr, - flags: ModuleInitFlags, -) -> Result<()> { - let res = unsafe { - libc::syscall( - libc::SYS_finit_module, - fd.as_raw_fd(), - param_values.as_ptr(), - flags.bits(), - ) - }; - - Errno::result(res).map(drop) -} - -libc_bitflags!( - /// Flags used by `delete_module`. - /// - /// See [`man delete_module(2)`](https://man7.org/linux/man-pages/man2/delete_module.2.html) - /// for a detailed description how these flags work. - pub struct DeleteModuleFlags: libc::c_int { - O_NONBLOCK; - O_TRUNC; - } -); - -/// Unloads the kernel module with the given name. -/// -/// # Example -/// -/// ```no_run -/// use std::ffi::CString; -/// use nix::kmod::{delete_module, DeleteModuleFlags}; -/// -/// delete_module(&CString::new("mymod").unwrap(), DeleteModuleFlags::O_NONBLOCK).unwrap(); -/// ``` -/// -/// See [`man delete_module(2)`](https://man7.org/linux/man-pages/man2/delete_module.2.html) for more information. -pub fn delete_module(name: &CStr, flags: DeleteModuleFlags) -> Result<()> { - let res = unsafe { - libc::syscall(libc::SYS_delete_module, name.as_ptr(), flags.bits()) - }; - - Errno::result(res).map(drop) -} diff --git a/vendor/nix/src/lib.rs b/vendor/nix/src/lib.rs deleted file mode 100644 index 6b8212576..000000000 --- a/vendor/nix/src/lib.rs +++ /dev/null @@ -1,333 +0,0 @@ -//! Rust friendly bindings to the various *nix system functions. -//! -//! Modules are structured according to the C header file that they would be -//! defined in. -//! -//! # Features -//! -//! Nix uses the following Cargo features to enable optional functionality. -//! They may be enabled in any combination. -//! * `acct` - Process accounting -//! * `aio` - POSIX AIO -//! * `dir` - Stuff relating to directory iteration -//! * `env` - Manipulate environment variables -//! * `event` - Event-driven APIs, like `kqueue` and `epoll` -//! * `feature` - Query characteristics of the OS at runtime -//! * `fs` - File system functionality -//! * `hostname` - Get and set the system's hostname -//! * `inotify` - Linux's `inotify` file system notification API -//! * `ioctl` - The `ioctl` syscall, and wrappers for my specific instances -//! * `kmod` - Load and unload kernel modules -//! * `mman` - Stuff relating to memory management -//! * `mount` - Mount and unmount file systems -//! * `mqueue` - POSIX message queues -//! * `net` - Networking-related functionality -//! * `personality` - Set the process execution domain -//! * `poll` - APIs like `poll` and `select` -//! * `process` - Stuff relating to running processes -//! * `pthread` - POSIX threads -//! * `ptrace` - Process tracing and debugging -//! * `quota` - File system quotas -//! * `reboot` - Reboot the system -//! * `resource` - Process resource limits -//! * `sched` - Manipulate process's scheduling -//! * `socket` - Sockets, whether for networking or local use -//! * `signal` - Send and receive signals to processes -//! * `term` - Terminal control APIs -//! * `time` - Query the operating system's clocks -//! * `ucontext` - User thread context -//! * `uio` - Vectored I/O -//! * `user` - Stuff relating to users and groups -//! * `zerocopy` - APIs like `sendfile` and `copy_file_range` -#![crate_name = "nix"] -#![cfg(unix)] -#![cfg_attr(docsrs, doc(cfg(all())))] -#![allow(non_camel_case_types)] -#![cfg_attr(test, deny(warnings))] -#![recursion_limit = "500"] -#![deny(unused)] -#![allow(unused_macros)] -#![cfg_attr(not(feature = "default"), allow(unused_imports))] -#![deny(unstable_features)] -#![deny(missing_copy_implementations)] -#![deny(missing_debug_implementations)] -#![warn(missing_docs)] -#![cfg_attr(docsrs, feature(doc_cfg))] -#![deny(clippy::cast_ptr_alignment)] - -// Re-exported external crates -pub use libc; - -// Private internal modules -#[macro_use] -mod macros; - -// Public crates -#[cfg(not(target_os = "redox"))] -feature! { - #![feature = "dir"] - pub mod dir; -} -feature! { - #![feature = "env"] - pub mod env; -} -#[allow(missing_docs)] -pub mod errno; -feature! { - #![feature = "feature"] - - #[deny(missing_docs)] - pub mod features; -} -#[allow(missing_docs)] -pub mod fcntl; -feature! { - #![feature = "net"] - - #[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "illumos", - target_os = "openbsd"))] - #[deny(missing_docs)] - pub mod ifaddrs; - #[cfg(not(target_os = "redox"))] - #[deny(missing_docs)] - pub mod net; -} -#[cfg(any(target_os = "android", target_os = "linux"))] -feature! { - #![feature = "kmod"] - #[allow(missing_docs)] - pub mod kmod; -} -feature! { - #![feature = "mount"] - pub mod mount; -} -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd" -))] -feature! { - #![feature = "mqueue"] - pub mod mqueue; -} -feature! { - #![feature = "poll"] - pub mod poll; -} -#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] -feature! { - #![feature = "term"] - #[deny(missing_docs)] - pub mod pty; -} -feature! { - #![feature = "sched"] - pub mod sched; -} -pub mod sys; -feature! { - #![feature = "time"] - #[allow(missing_docs)] - pub mod time; -} -// This can be implemented for other platforms as soon as libc -// provides bindings for them. -#[cfg(all( - target_os = "linux", - any(target_arch = "s390x", target_arch = "x86", target_arch = "x86_64") -))] -feature! { - #![feature = "ucontext"] - #[allow(missing_docs)] - pub mod ucontext; -} -#[allow(missing_docs)] -pub mod unistd; - -use std::ffi::{CStr, CString, OsStr}; -use std::mem::MaybeUninit; -use std::os::unix::ffi::OsStrExt; -use std::path::{Path, PathBuf}; -use std::{ptr, result, slice}; - -use errno::Errno; - -/// Nix Result Type -pub type Result<T> = result::Result<T, Errno>; - -/// Nix's main error type. -/// -/// It's a wrapper around Errno. As such, it's very interoperable with -/// [`std::io::Error`], but it has the advantages of: -/// * `Clone` -/// * `Copy` -/// * `Eq` -/// * Small size -/// * Represents all of the system's errnos, instead of just the most common -/// ones. -pub type Error = Errno; - -/// Common trait used to represent file system paths by many Nix functions. -pub trait NixPath { - /// Is the path empty? - fn is_empty(&self) -> bool; - - /// Length of the path in bytes - fn len(&self) -> usize; - - /// Execute a function with this path as a `CStr`. - /// - /// Mostly used internally by Nix. - fn with_nix_path<T, F>(&self, f: F) -> Result<T> - where - F: FnOnce(&CStr) -> T; -} - -impl NixPath for str { - fn is_empty(&self) -> bool { - NixPath::is_empty(OsStr::new(self)) - } - - fn len(&self) -> usize { - NixPath::len(OsStr::new(self)) - } - - fn with_nix_path<T, F>(&self, f: F) -> Result<T> - where - F: FnOnce(&CStr) -> T, - { - OsStr::new(self).with_nix_path(f) - } -} - -impl NixPath for OsStr { - fn is_empty(&self) -> bool { - self.as_bytes().is_empty() - } - - fn len(&self) -> usize { - self.as_bytes().len() - } - - fn with_nix_path<T, F>(&self, f: F) -> Result<T> - where - F: FnOnce(&CStr) -> T, - { - self.as_bytes().with_nix_path(f) - } -} - -impl NixPath for CStr { - fn is_empty(&self) -> bool { - self.to_bytes().is_empty() - } - - fn len(&self) -> usize { - self.to_bytes().len() - } - - fn with_nix_path<T, F>(&self, f: F) -> Result<T> - where - F: FnOnce(&CStr) -> T, - { - Ok(f(self)) - } -} - -impl NixPath for [u8] { - fn is_empty(&self) -> bool { - self.is_empty() - } - - fn len(&self) -> usize { - self.len() - } - - fn with_nix_path<T, F>(&self, f: F) -> Result<T> - where - F: FnOnce(&CStr) -> T, - { - // The real PATH_MAX is typically 4096, but it's statistically unlikely to have a path - // longer than ~300 bytes. See the the PR description to get stats for your own machine. - // https://github.com/nix-rust/nix/pull/1656 - // - // By being smaller than a memory page, we also avoid the compiler inserting a probe frame: - // https://docs.rs/compiler_builtins/latest/compiler_builtins/probestack/index.html - const MAX_STACK_ALLOCATION: usize = 1024; - - if self.len() >= MAX_STACK_ALLOCATION { - return with_nix_path_allocating(self, f); - } - - let mut buf = MaybeUninit::<[u8; MAX_STACK_ALLOCATION]>::uninit(); - let buf_ptr = buf.as_mut_ptr() as *mut u8; - - unsafe { - ptr::copy_nonoverlapping(self.as_ptr(), buf_ptr, self.len()); - buf_ptr.add(self.len()).write(0); - } - - match CStr::from_bytes_with_nul(unsafe { - slice::from_raw_parts(buf_ptr, self.len() + 1) - }) { - Ok(s) => Ok(f(s)), - Err(_) => Err(Errno::EINVAL), - } - } -} - -#[cold] -#[inline(never)] -fn with_nix_path_allocating<T, F>(from: &[u8], f: F) -> Result<T> -where - F: FnOnce(&CStr) -> T, -{ - match CString::new(from) { - Ok(s) => Ok(f(&s)), - Err(_) => Err(Errno::EINVAL), - } -} - -impl NixPath for Path { - fn is_empty(&self) -> bool { - NixPath::is_empty(self.as_os_str()) - } - - fn len(&self) -> usize { - NixPath::len(self.as_os_str()) - } - - fn with_nix_path<T, F>(&self, f: F) -> Result<T> - where - F: FnOnce(&CStr) -> T, - { - self.as_os_str().with_nix_path(f) - } -} - -impl NixPath for PathBuf { - fn is_empty(&self) -> bool { - NixPath::is_empty(self.as_os_str()) - } - - fn len(&self) -> usize { - NixPath::len(self.as_os_str()) - } - - fn with_nix_path<T, F>(&self, f: F) -> Result<T> - where - F: FnOnce(&CStr) -> T, - { - self.as_os_str().with_nix_path(f) - } -} diff --git a/vendor/nix/src/macros.rs b/vendor/nix/src/macros.rs deleted file mode 100644 index 99e0de886..000000000 --- a/vendor/nix/src/macros.rs +++ /dev/null @@ -1,328 +0,0 @@ -// Thanks to Tokio for this macro -macro_rules! feature { - ( - #![$meta:meta] - $($item:item)* - ) => { - $( - #[cfg($meta)] - #[cfg_attr(docsrs, doc(cfg($meta)))] - $item - )* - } -} - -/// The `libc_bitflags!` macro helps with a common use case of defining a public bitflags type -/// with values from the libc crate. It is used the same way as the `bitflags!` macro, except -/// that only the name of the flag value has to be given. -/// -/// The `libc` crate must be in scope with the name `libc`. -/// -/// # Example -/// ```ignore -/// libc_bitflags!{ -/// pub struct ProtFlags: libc::c_int { -/// PROT_NONE; -/// PROT_READ; -/// /// PROT_WRITE enables write protect -/// PROT_WRITE; -/// PROT_EXEC; -/// #[cfg(any(target_os = "linux", target_os = "android"))] -/// PROT_GROWSDOWN; -/// #[cfg(any(target_os = "linux", target_os = "android"))] -/// PROT_GROWSUP; -/// } -/// } -/// ``` -/// -/// Example with casting, due to a mistake in libc. In this example, the -/// various flags have different types, so we cast the broken ones to the right -/// type. -/// -/// ```ignore -/// libc_bitflags!{ -/// pub struct SaFlags: libc::c_ulong { -/// SA_NOCLDSTOP as libc::c_ulong; -/// SA_NOCLDWAIT; -/// SA_NODEFER as libc::c_ulong; -/// SA_ONSTACK; -/// SA_RESETHAND as libc::c_ulong; -/// SA_RESTART as libc::c_ulong; -/// SA_SIGINFO; -/// } -/// } -/// ``` -macro_rules! libc_bitflags { - ( - $(#[$outer:meta])* - pub struct $BitFlags:ident: $T:ty { - $( - $(#[$inner:ident $($args:tt)*])* - $Flag:ident $(as $cast:ty)*; - )+ - } - ) => { - ::bitflags::bitflags! { - $(#[$outer])* - pub struct $BitFlags: $T { - $( - $(#[$inner $($args)*])* - const $Flag = libc::$Flag $(as $cast)*; - )+ - } - } - }; -} - -/// The `libc_enum!` macro helps with a common use case of defining an enum exclusively using -/// values from the `libc` crate. This macro supports both `pub` and private `enum`s. -/// -/// The `libc` crate must be in scope with the name `libc`. -/// -/// # Example -/// ```ignore -/// libc_enum!{ -/// pub enum ProtFlags { -/// PROT_NONE, -/// PROT_READ, -/// PROT_WRITE, -/// PROT_EXEC, -/// #[cfg(any(target_os = "linux", target_os = "android"))] -/// PROT_GROWSDOWN, -/// #[cfg(any(target_os = "linux", target_os = "android"))] -/// PROT_GROWSUP, -/// } -/// } -/// ``` -// Some targets don't use all rules. -#[allow(unknown_lints)] -#[allow(unused_macro_rules)] -macro_rules! libc_enum { - // Exit rule. - (@make_enum - name: $BitFlags:ident, - { - $v:vis - attrs: [$($attrs:tt)*], - entries: [$($entries:tt)*], - } - ) => { - $($attrs)* - #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] - $v enum $BitFlags { - $($entries)* - } - }; - - // Exit rule including TryFrom - (@make_enum - name: $BitFlags:ident, - { - $v:vis - attrs: [$($attrs:tt)*], - entries: [$($entries:tt)*], - from_type: $repr:path, - try_froms: [$($try_froms:tt)*] - } - ) => { - $($attrs)* - #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] - $v enum $BitFlags { - $($entries)* - } - impl ::std::convert::TryFrom<$repr> for $BitFlags { - type Error = $crate::Error; - #[allow(unused_doc_comments)] - fn try_from(x: $repr) -> $crate::Result<Self> { - match x { - $($try_froms)* - _ => Err($crate::Error::EINVAL) - } - } - } - }; - - // Done accumulating. - (@accumulate_entries - name: $BitFlags:ident, - { - $v:vis - attrs: $attrs:tt, - }, - $entries:tt, - $try_froms:tt; - ) => { - libc_enum! { - @make_enum - name: $BitFlags, - { - $v - attrs: $attrs, - entries: $entries, - } - } - }; - - // Done accumulating and want TryFrom - (@accumulate_entries - name: $BitFlags:ident, - { - $v:vis - attrs: $attrs:tt, - from_type: $repr:path, - }, - $entries:tt, - $try_froms:tt; - ) => { - libc_enum! { - @make_enum - name: $BitFlags, - { - $v - attrs: $attrs, - entries: $entries, - from_type: $repr, - try_froms: $try_froms - } - } - }; - - // Munch an attr. - (@accumulate_entries - name: $BitFlags:ident, - $prefix:tt, - [$($entries:tt)*], - [$($try_froms:tt)*]; - #[$attr:meta] $($tail:tt)* - ) => { - libc_enum! { - @accumulate_entries - name: $BitFlags, - $prefix, - [ - $($entries)* - #[$attr] - ], - [ - $($try_froms)* - #[$attr] - ]; - $($tail)* - } - }; - - // Munch last ident if not followed by a comma. - (@accumulate_entries - name: $BitFlags:ident, - $prefix:tt, - [$($entries:tt)*], - [$($try_froms:tt)*]; - $entry:ident - ) => { - libc_enum! { - @accumulate_entries - name: $BitFlags, - $prefix, - [ - $($entries)* - $entry = libc::$entry, - ], - [ - $($try_froms)* - libc::$entry => Ok($BitFlags::$entry), - ]; - } - }; - - // Munch an ident; covers terminating comma case. - (@accumulate_entries - name: $BitFlags:ident, - $prefix:tt, - [$($entries:tt)*], - [$($try_froms:tt)*]; - $entry:ident, - $($tail:tt)* - ) => { - libc_enum! { - @accumulate_entries - name: $BitFlags, - $prefix, - [ - $($entries)* - $entry = libc::$entry, - ], - [ - $($try_froms)* - libc::$entry => Ok($BitFlags::$entry), - ]; - $($tail)* - } - }; - - // Munch an ident and cast it to the given type; covers terminating comma. - (@accumulate_entries - name: $BitFlags:ident, - $prefix:tt, - [$($entries:tt)*], - [$($try_froms:tt)*]; - $entry:ident as $ty:ty, - $($tail:tt)* - ) => { - libc_enum! { - @accumulate_entries - name: $BitFlags, - $prefix, - [ - $($entries)* - $entry = libc::$entry as $ty, - ], - [ - $($try_froms)* - libc::$entry as $ty => Ok($BitFlags::$entry), - ]; - $($tail)* - } - }; - - // Entry rule. - ( - $(#[$attr:meta])* - $v:vis enum $BitFlags:ident { - $($vals:tt)* - } - ) => { - libc_enum! { - @accumulate_entries - name: $BitFlags, - { - $v - attrs: [$(#[$attr])*], - }, - [], - []; - $($vals)* - } - }; - - // Entry rule including TryFrom - ( - $(#[$attr:meta])* - $v:vis enum $BitFlags:ident { - $($vals:tt)* - } - impl TryFrom<$repr:path> - ) => { - libc_enum! { - @accumulate_entries - name: $BitFlags, - { - $v - attrs: [$(#[$attr])*], - from_type: $repr, - }, - [], - []; - $($vals)* - } - }; -} diff --git a/vendor/nix/src/mount/bsd.rs b/vendor/nix/src/mount/bsd.rs deleted file mode 100644 index d124f1f9a..000000000 --- a/vendor/nix/src/mount/bsd.rs +++ /dev/null @@ -1,453 +0,0 @@ -#[cfg(target_os = "freebsd")] -use crate::Error; -use crate::{Errno, NixPath, Result}; -use libc::c_int; -#[cfg(target_os = "freebsd")] -use libc::{c_char, c_uint, c_void}; -#[cfg(target_os = "freebsd")] -use std::{ - borrow::Cow, - ffi::{CStr, CString}, - fmt, io, - marker::PhantomData, -}; - -libc_bitflags!( - /// Used with [`Nmount::nmount`]. - pub struct MntFlags: c_int { - /// ACL support enabled. - #[cfg(any(target_os = "netbsd", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MNT_ACLS; - /// All I/O to the file system should be done asynchronously. - MNT_ASYNC; - /// dir should instead be a file system ID encoded as “FSID:val0:val1”. - #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MNT_BYFSID; - /// Force a read-write mount even if the file system appears to be - /// unclean. - MNT_FORCE; - /// GEOM journal support enabled. - #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MNT_GJOURNAL; - /// MAC support for objects. - #[cfg(any(target_os = "macos", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MNT_MULTILABEL; - /// Disable read clustering. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MNT_NOCLUSTERR; - /// Disable write clustering. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MNT_NOCLUSTERW; - /// Enable NFS version 4 ACLs. - #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MNT_NFS4ACLS; - /// Do not update access times. - MNT_NOATIME; - /// Disallow program execution. - MNT_NOEXEC; - /// Do not honor setuid or setgid bits on files when executing them. - MNT_NOSUID; - /// Do not follow symlinks. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MNT_NOSYMFOLLOW; - /// Mount read-only. - MNT_RDONLY; - /// Causes the vfs subsystem to update its data structures pertaining to - /// the specified already mounted file system. - MNT_RELOAD; - /// Create a snapshot of the file system. - /// - /// See [mksnap_ffs(8)](https://www.freebsd.org/cgi/man.cgi?query=mksnap_ffs) - #[cfg(any(target_os = "macos", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MNT_SNAPSHOT; - /// Using soft updates. - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MNT_SOFTDEP; - /// Directories with the SUID bit set chown new files to their own - /// owner. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MNT_SUIDDIR; - /// All I/O to the file system should be done synchronously. - MNT_SYNCHRONOUS; - /// Union with underlying fs. - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "netbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MNT_UNION; - /// Indicates that the mount command is being applied to an already - /// mounted file system. - MNT_UPDATE; - /// Check vnode use counts. - #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MNT_NONBUSY; - } -); - -/// The Error type of [`Nmount::nmount`]. -/// -/// It wraps an [`Errno`], but also may contain an additional message returned -/// by `nmount(2)`. -#[cfg(target_os = "freebsd")] -#[derive(Debug)] -pub struct NmountError { - errno: Error, - errmsg: Option<String>, -} - -#[cfg(target_os = "freebsd")] -impl NmountError { - /// Returns the additional error string sometimes generated by `nmount(2)`. - pub fn errmsg(&self) -> Option<&str> { - self.errmsg.as_deref() - } - - /// Returns the inner [`Error`] - pub const fn error(&self) -> Error { - self.errno - } - - fn new(error: Error, errmsg: Option<&CStr>) -> Self { - Self { - errno: error, - errmsg: errmsg.map(CStr::to_string_lossy).map(Cow::into_owned), - } - } -} - -#[cfg(target_os = "freebsd")] -impl std::error::Error for NmountError {} - -#[cfg(target_os = "freebsd")] -impl fmt::Display for NmountError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if let Some(errmsg) = &self.errmsg { - write!(f, "{:?}: {}: {}", self.errno, errmsg, self.errno.desc()) - } else { - write!(f, "{:?}: {}", self.errno, self.errno.desc()) - } - } -} - -#[cfg(target_os = "freebsd")] -impl From<NmountError> for io::Error { - fn from(err: NmountError) -> Self { - err.errno.into() - } -} - -/// Result type of [`Nmount::nmount`]. -#[cfg(target_os = "freebsd")] -pub type NmountResult = std::result::Result<(), NmountError>; - -/// Mount a FreeBSD file system. -/// -/// The `nmount(2)` system call works similarly to the `mount(8)` program; it -/// takes its options as a series of name-value pairs. Most of the values are -/// strings, as are all of the names. The `Nmount` structure builds up an -/// argument list and then executes the syscall. -/// -/// # Examples -/// -/// To mount `target` onto `mountpoint` with `nullfs`: -/// ``` -/// # use nix::unistd::Uid; -/// # use ::sysctl::{CtlValue, Sysctl}; -/// # let ctl = ::sysctl::Ctl::new("vfs.usermount").unwrap(); -/// # if !Uid::current().is_root() && CtlValue::Int(0) == ctl.value().unwrap() { -/// # return; -/// # }; -/// use nix::mount::{MntFlags, Nmount, unmount}; -/// use std::ffi::CString; -/// use tempfile::tempdir; -/// -/// let mountpoint = tempdir().unwrap(); -/// let target = tempdir().unwrap(); -/// -/// let fstype = CString::new("fstype").unwrap(); -/// let nullfs = CString::new("nullfs").unwrap(); -/// Nmount::new() -/// .str_opt(&fstype, &nullfs) -/// .str_opt_owned("fspath", mountpoint.path().to_str().unwrap()) -/// .str_opt_owned("target", target.path().to_str().unwrap()) -/// .nmount(MntFlags::empty()).unwrap(); -/// -/// unmount(mountpoint.path(), MntFlags::empty()).unwrap(); -/// ``` -/// -/// # See Also -/// * [`nmount(2)`](https://www.freebsd.org/cgi/man.cgi?query=nmount) -/// * [`nullfs(5)`](https://www.freebsd.org/cgi/man.cgi?query=nullfs) -#[cfg(target_os = "freebsd")] -#[cfg_attr(docsrs, doc(cfg(all())))] -#[derive(Debug, Default)] -pub struct Nmount<'a> { - // n.b. notgull: In reality, this is a list that contains - // both mutable and immutable pointers. - // Be careful using this. - iov: Vec<libc::iovec>, - is_owned: Vec<bool>, - marker: PhantomData<&'a ()>, -} - -#[cfg(target_os = "freebsd")] -#[cfg_attr(docsrs, doc(cfg(all())))] -impl<'a> Nmount<'a> { - /// Helper function to push a slice onto the `iov` array. - fn push_slice(&mut self, val: &'a [u8], is_owned: bool) { - self.iov.push(libc::iovec { - iov_base: val.as_ptr() as *mut _, - iov_len: val.len(), - }); - self.is_owned.push(is_owned); - } - - /// Helper function to push a pointer and its length onto the `iov` array. - fn push_pointer_and_length( - &mut self, - val: *const u8, - len: usize, - is_owned: bool, - ) { - self.iov.push(libc::iovec { - iov_base: val as *mut _, - iov_len: len, - }); - self.is_owned.push(is_owned); - } - - /// Helper function to push a `nix` path as owned. - fn push_nix_path<P: ?Sized + NixPath>(&mut self, val: &P) { - val.with_nix_path(|s| { - let len = s.to_bytes_with_nul().len(); - let ptr = s.to_owned().into_raw() as *const u8; - - self.push_pointer_and_length(ptr, len, true); - }) - .unwrap(); - } - - /// Add an opaque mount option. - /// - /// Some file systems take binary-valued mount options. They can be set - /// with this method. - /// - /// # Safety - /// - /// Unsafe because it will cause `Nmount::nmount` to dereference a raw - /// pointer. The user is responsible for ensuring that `val` is valid and - /// its lifetime outlives `self`! An easy way to do that is to give the - /// value a larger scope than `name` - /// - /// # Examples - /// ``` - /// use libc::c_void; - /// use nix::mount::Nmount; - /// use std::ffi::CString; - /// use std::mem; - /// - /// // Note that flags outlives name - /// let mut flags: u32 = 0xdeadbeef; - /// let name = CString::new("flags").unwrap(); - /// let p = &mut flags as *mut u32 as *mut c_void; - /// let len = mem::size_of_val(&flags); - /// let mut nmount = Nmount::new(); - /// unsafe { nmount.mut_ptr_opt(&name, p, len) }; - /// ``` - pub unsafe fn mut_ptr_opt( - &mut self, - name: &'a CStr, - val: *mut c_void, - len: usize, - ) -> &mut Self { - self.push_slice(name.to_bytes_with_nul(), false); - self.push_pointer_and_length(val.cast(), len, false); - self - } - - /// Add a mount option that does not take a value. - /// - /// # Examples - /// ``` - /// use nix::mount::Nmount; - /// use std::ffi::CString; - /// - /// let read_only = CString::new("ro").unwrap(); - /// Nmount::new() - /// .null_opt(&read_only); - /// ``` - pub fn null_opt(&mut self, name: &'a CStr) -> &mut Self { - self.push_slice(name.to_bytes_with_nul(), false); - self.push_slice(&[], false); - self - } - - /// Add a mount option that does not take a value, but whose name must be - /// owned. - /// - /// - /// This has higher runtime cost than [`Nmount::null_opt`], but is useful - /// when the name's lifetime doesn't outlive the `Nmount`, or it's a - /// different string type than `CStr`. - /// - /// # Examples - /// ``` - /// use nix::mount::Nmount; - /// - /// let read_only = "ro"; - /// let mut nmount: Nmount<'static> = Nmount::new(); - /// nmount.null_opt_owned(read_only); - /// ``` - pub fn null_opt_owned<P: ?Sized + NixPath>( - &mut self, - name: &P, - ) -> &mut Self { - self.push_nix_path(name); - self.push_slice(&[], false); - self - } - - /// Add a mount option as a [`CStr`]. - /// - /// # Examples - /// ``` - /// use nix::mount::Nmount; - /// use std::ffi::CString; - /// - /// let fstype = CString::new("fstype").unwrap(); - /// let nullfs = CString::new("nullfs").unwrap(); - /// Nmount::new() - /// .str_opt(&fstype, &nullfs); - /// ``` - pub fn str_opt(&mut self, name: &'a CStr, val: &'a CStr) -> &mut Self { - self.push_slice(name.to_bytes_with_nul(), false); - self.push_slice(val.to_bytes_with_nul(), false); - self - } - - /// Add a mount option as an owned string. - /// - /// This has higher runtime cost than [`Nmount::str_opt`], but is useful - /// when the value's lifetime doesn't outlive the `Nmount`, or it's a - /// different string type than `CStr`. - /// - /// # Examples - /// ``` - /// use nix::mount::Nmount; - /// use std::path::Path; - /// - /// let mountpoint = Path::new("/mnt"); - /// Nmount::new() - /// .str_opt_owned("fspath", mountpoint.to_str().unwrap()); - /// ``` - pub fn str_opt_owned<P1, P2>(&mut self, name: &P1, val: &P2) -> &mut Self - where - P1: ?Sized + NixPath, - P2: ?Sized + NixPath, - { - self.push_nix_path(name); - self.push_nix_path(val); - self - } - - /// Create a new `Nmount` struct with no options - pub fn new() -> Self { - Self::default() - } - - /// Actually mount the file system. - pub fn nmount(&mut self, flags: MntFlags) -> NmountResult { - const ERRMSG_NAME: &[u8] = b"errmsg\0"; - let mut errmsg = vec![0u8; 255]; - - // nmount can return extra error information via a "errmsg" return - // argument. - self.push_slice(ERRMSG_NAME, false); - - // SAFETY: we are pushing a mutable iovec here, so we can't use - // the above method - self.iov.push(libc::iovec { - iov_base: errmsg.as_mut_ptr() as *mut c_void, - iov_len: errmsg.len(), - }); - - let niov = self.iov.len() as c_uint; - let iovp = self.iov.as_mut_ptr() as *mut libc::iovec; - let res = unsafe { libc::nmount(iovp, niov, flags.bits) }; - match Errno::result(res) { - Ok(_) => Ok(()), - Err(error) => { - let errmsg = match errmsg.iter().position(|&x| x == 0) { - None => None, - Some(0) => None, - Some(n) => { - let sl = &errmsg[0..n + 1]; - Some(CStr::from_bytes_with_nul(sl).unwrap()) - } - }; - Err(NmountError::new(error, errmsg)) - } - } - } -} - -#[cfg(target_os = "freebsd")] -impl<'a> Drop for Nmount<'a> { - fn drop(&mut self) { - for (iov, is_owned) in self.iov.iter().zip(self.is_owned.iter()) { - if *is_owned { - // Free the owned string. Safe because we recorded ownership, - // and Nmount does not implement Clone. - unsafe { - drop(CString::from_raw(iov.iov_base as *mut c_char)); - } - } - } - } -} - -/// Unmount the file system mounted at `mountpoint`. -/// -/// Useful flags include -/// * `MNT_FORCE` - Unmount even if still in use. -#[cfg_attr( - target_os = "freebsd", - doc = " -* `MNT_BYFSID` - `mountpoint` is not a path, but a file system ID - encoded as `FSID:val0:val1`, where `val0` and `val1` - are the contents of the `fsid_t val[]` array in decimal. - The file system that has the specified file system ID - will be unmounted. See - [`statfs`](crate::sys::statfs::statfs) to determine the - `fsid`. -" -)] -pub fn unmount<P>(mountpoint: &P, flags: MntFlags) -> Result<()> -where - P: ?Sized + NixPath, -{ - let res = mountpoint.with_nix_path(|cstr| unsafe { - libc::unmount(cstr.as_ptr(), flags.bits) - })?; - - Errno::result(res).map(drop) -} diff --git a/vendor/nix/src/mount/linux.rs b/vendor/nix/src/mount/linux.rs deleted file mode 100644 index cf6a60b01..000000000 --- a/vendor/nix/src/mount/linux.rs +++ /dev/null @@ -1,115 +0,0 @@ -#![allow(missing_docs)] -use crate::errno::Errno; -use crate::{NixPath, Result}; -use libc::{self, c_int, c_ulong}; - -libc_bitflags!( - pub struct MsFlags: c_ulong { - /// Mount read-only - MS_RDONLY; - /// Ignore suid and sgid bits - MS_NOSUID; - /// Disallow access to device special files - MS_NODEV; - /// Disallow program execution - MS_NOEXEC; - /// Writes are synced at once - MS_SYNCHRONOUS; - /// Alter flags of a mounted FS - MS_REMOUNT; - /// Allow mandatory locks on a FS - MS_MANDLOCK; - /// Directory modifications are synchronous - MS_DIRSYNC; - /// Do not update access times - MS_NOATIME; - /// Do not update directory access times - MS_NODIRATIME; - /// Linux 2.4.0 - Bind directory at different place - MS_BIND; - MS_MOVE; - MS_REC; - MS_SILENT; - MS_POSIXACL; - MS_UNBINDABLE; - MS_PRIVATE; - MS_SLAVE; - MS_SHARED; - MS_RELATIME; - MS_KERNMOUNT; - MS_I_VERSION; - MS_STRICTATIME; - MS_LAZYTIME; - MS_ACTIVE; - MS_NOUSER; - MS_RMT_MASK; - MS_MGC_VAL; - MS_MGC_MSK; - } -); - -libc_bitflags!( - pub struct MntFlags: c_int { - MNT_FORCE; - MNT_DETACH; - MNT_EXPIRE; - UMOUNT_NOFOLLOW; - } -); - -pub fn mount< - P1: ?Sized + NixPath, - P2: ?Sized + NixPath, - P3: ?Sized + NixPath, - P4: ?Sized + NixPath, ->( - source: Option<&P1>, - target: &P2, - fstype: Option<&P3>, - flags: MsFlags, - data: Option<&P4>, -) -> Result<()> { - fn with_opt_nix_path<P, T, F>(p: Option<&P>, f: F) -> Result<T> - where - P: ?Sized + NixPath, - F: FnOnce(*const libc::c_char) -> T, - { - match p { - Some(path) => path.with_nix_path(|p_str| f(p_str.as_ptr())), - None => Ok(f(std::ptr::null())), - } - } - - let res = with_opt_nix_path(source, |s| { - target.with_nix_path(|t| { - with_opt_nix_path(fstype, |ty| { - with_opt_nix_path(data, |d| unsafe { - libc::mount( - s, - t.as_ptr(), - ty, - flags.bits, - d as *const libc::c_void, - ) - }) - }) - }) - })????; - - Errno::result(res).map(drop) -} - -pub fn umount<P: ?Sized + NixPath>(target: &P) -> Result<()> { - let res = - target.with_nix_path(|cstr| unsafe { libc::umount(cstr.as_ptr()) })?; - - Errno::result(res).map(drop) -} - -pub fn umount2<P: ?Sized + NixPath>(target: &P, flags: MntFlags) -> Result<()> { - let res = target.with_nix_path(|cstr| unsafe { - libc::umount2(cstr.as_ptr(), flags.bits) - })?; - - Errno::result(res).map(drop) -} diff --git a/vendor/nix/src/mount/mod.rs b/vendor/nix/src/mount/mod.rs deleted file mode 100644 index e98b49c34..000000000 --- a/vendor/nix/src/mount/mod.rs +++ /dev/null @@ -1,26 +0,0 @@ -//! Mount file systems -#[cfg(any(target_os = "android", target_os = "linux"))] -#[cfg_attr(docsrs, doc(cfg(all())))] -mod linux; - -#[cfg(any(target_os = "android", target_os = "linux"))] -pub use self::linux::*; - -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" -))] -#[cfg_attr(docsrs, doc(cfg(all())))] -mod bsd; - -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" -))] -pub use self::bsd::*; diff --git a/vendor/nix/src/mqueue.rs b/vendor/nix/src/mqueue.rs deleted file mode 100644 index 33599bf91..000000000 --- a/vendor/nix/src/mqueue.rs +++ /dev/null @@ -1,276 +0,0 @@ -//! Posix Message Queue functions -//! -//! # Example -//! -// no_run because a kernel module may be required. -//! ```no_run -//! # use std::ffi::CString; -//! # use nix::mqueue::*; -//! use nix::sys::stat::Mode; -//! -//! const MSG_SIZE: mq_attr_member_t = 32; -//! let mq_name= CString::new("/a_nix_test_queue").unwrap(); -//! -//! let oflag0 = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; -//! let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; -//! let mqd0 = mq_open(&mq_name, oflag0, mode, None).unwrap(); -//! let msg_to_send = b"msg_1"; -//! mq_send(&mqd0, msg_to_send, 1).unwrap(); -//! -//! let oflag1 = MQ_OFlag::O_CREAT | MQ_OFlag::O_RDONLY; -//! let mqd1 = mq_open(&mq_name, oflag1, mode, None).unwrap(); -//! let mut buf = [0u8; 32]; -//! let mut prio = 0u32; -//! let len = mq_receive(&mqd1, &mut buf, &mut prio).unwrap(); -//! assert_eq!(prio, 1); -//! assert_eq!(msg_to_send, &buf[0..len]); -//! -//! mq_close(mqd1).unwrap(); -//! mq_close(mqd0).unwrap(); -//! ``` -//! [Further reading and details on the C API](https://man7.org/linux/man-pages/man7/mq_overview.7.html) - -use crate::errno::Errno; -use crate::Result; - -use crate::sys::stat::Mode; -use libc::{self, c_char, mqd_t, size_t}; -use std::ffi::CStr; -use std::mem; - -libc_bitflags! { - /// Used with [`mq_open`]. - pub struct MQ_OFlag: libc::c_int { - /// Open the message queue for receiving messages. - O_RDONLY; - /// Open the queue for sending messages. - O_WRONLY; - /// Open the queue for both receiving and sending messages - O_RDWR; - /// Create a message queue. - O_CREAT; - /// If set along with `O_CREAT`, `mq_open` will fail if the message - /// queue name exists. - O_EXCL; - /// `mq_send` and `mq_receive` should fail with `EAGAIN` rather than - /// wait for resources that are not currently available. - O_NONBLOCK; - /// Set the close-on-exec flag for the message queue descriptor. - O_CLOEXEC; - } -} - -/// A message-queue attribute, optionally used with [`mq_setattr`] and -/// [`mq_getattr`] and optionally [`mq_open`], -#[repr(C)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct MqAttr { - mq_attr: libc::mq_attr, -} - -/// Identifies an open POSIX Message Queue -// A safer wrapper around libc::mqd_t, which is a pointer on some platforms -// Deliberately is not Clone to prevent use-after-close scenarios -#[repr(transparent)] -#[derive(Debug)] -#[allow(missing_copy_implementations)] -pub struct MqdT(mqd_t); - -// x32 compatibility -// See https://sourceware.org/bugzilla/show_bug.cgi?id=21279 -/// Size of a message queue attribute member -#[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub type mq_attr_member_t = i64; -/// Size of a message queue attribute member -#[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub type mq_attr_member_t = libc::c_long; - -impl MqAttr { - /// Create a new message queue attribute - /// - /// # Arguments - /// - /// - `mq_flags`: Either `0` or `O_NONBLOCK`. - /// - `mq_maxmsg`: Maximum number of messages on the queue. - /// - `mq_msgsize`: Maximum message size in bytes. - /// - `mq_curmsgs`: Number of messages currently in the queue. - pub fn new( - mq_flags: mq_attr_member_t, - mq_maxmsg: mq_attr_member_t, - mq_msgsize: mq_attr_member_t, - mq_curmsgs: mq_attr_member_t, - ) -> MqAttr { - let mut attr = mem::MaybeUninit::<libc::mq_attr>::uninit(); - unsafe { - let p = attr.as_mut_ptr(); - (*p).mq_flags = mq_flags; - (*p).mq_maxmsg = mq_maxmsg; - (*p).mq_msgsize = mq_msgsize; - (*p).mq_curmsgs = mq_curmsgs; - MqAttr { - mq_attr: attr.assume_init(), - } - } - } - - /// The current flags, either `0` or `O_NONBLOCK`. - pub const fn flags(&self) -> mq_attr_member_t { - self.mq_attr.mq_flags - } - - /// The max number of messages that can be held by the queue - pub const fn maxmsg(&self) -> mq_attr_member_t { - self.mq_attr.mq_maxmsg - } - - /// The maximum size of each message (in bytes) - pub const fn msgsize(&self) -> mq_attr_member_t { - self.mq_attr.mq_msgsize - } - - /// The number of messages currently held in the queue - pub const fn curmsgs(&self) -> mq_attr_member_t { - self.mq_attr.mq_curmsgs - } -} - -/// Open a message queue -/// -/// See also [`mq_open(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_open.html) -// The mode.bits cast is only lossless on some OSes -#[allow(clippy::cast_lossless)] -pub fn mq_open( - name: &CStr, - oflag: MQ_OFlag, - mode: Mode, - attr: Option<&MqAttr>, -) -> Result<MqdT> { - let res = match attr { - Some(mq_attr) => unsafe { - libc::mq_open( - name.as_ptr(), - oflag.bits(), - mode.bits() as libc::c_int, - &mq_attr.mq_attr as *const libc::mq_attr, - ) - }, - None => unsafe { libc::mq_open(name.as_ptr(), oflag.bits()) }, - }; - Errno::result(res).map(MqdT) -} - -/// Remove a message queue -/// -/// See also [`mq_unlink(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_unlink.html) -pub fn mq_unlink(name: &CStr) -> Result<()> { - let res = unsafe { libc::mq_unlink(name.as_ptr()) }; - Errno::result(res).map(drop) -} - -/// Close a message queue -/// -/// See also [`mq_close(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_close.html) -pub fn mq_close(mqdes: MqdT) -> Result<()> { - let res = unsafe { libc::mq_close(mqdes.0) }; - Errno::result(res).map(drop) -} - -/// Receive a message from a message queue -/// -/// See also [`mq_receive(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_receive.html) -pub fn mq_receive( - mqdes: &MqdT, - message: &mut [u8], - msg_prio: &mut u32, -) -> Result<usize> { - let len = message.len() as size_t; - let res = unsafe { - libc::mq_receive( - mqdes.0, - message.as_mut_ptr() as *mut c_char, - len, - msg_prio as *mut u32, - ) - }; - Errno::result(res).map(|r| r as usize) -} - -/// Send a message to a message queue -/// -/// See also [`mq_send(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_send.html) -pub fn mq_send(mqdes: &MqdT, message: &[u8], msq_prio: u32) -> Result<()> { - let res = unsafe { - libc::mq_send( - mqdes.0, - message.as_ptr() as *const c_char, - message.len(), - msq_prio, - ) - }; - Errno::result(res).map(drop) -} - -/// Get message queue attributes -/// -/// See also [`mq_getattr(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_getattr.html) -pub fn mq_getattr(mqd: &MqdT) -> Result<MqAttr> { - let mut attr = mem::MaybeUninit::<libc::mq_attr>::uninit(); - let res = unsafe { libc::mq_getattr(mqd.0, attr.as_mut_ptr()) }; - Errno::result(res).map(|_| unsafe { - MqAttr { - mq_attr: attr.assume_init(), - } - }) -} - -/// Set the attributes of the message queue. Only `O_NONBLOCK` can be set, everything else will be ignored -/// Returns the old attributes -/// It is recommend to use the `mq_set_nonblock()` and `mq_remove_nonblock()` convenience functions as they are easier to use -/// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_setattr.html) -pub fn mq_setattr(mqd: &MqdT, newattr: &MqAttr) -> Result<MqAttr> { - let mut attr = mem::MaybeUninit::<libc::mq_attr>::uninit(); - let res = unsafe { - libc::mq_setattr( - mqd.0, - &newattr.mq_attr as *const libc::mq_attr, - attr.as_mut_ptr(), - ) - }; - Errno::result(res).map(|_| unsafe { - MqAttr { - mq_attr: attr.assume_init(), - } - }) -} - -/// Convenience function. -/// Sets the `O_NONBLOCK` attribute for a given message queue descriptor -/// Returns the old attributes -#[allow(clippy::useless_conversion)] // Not useless on all OSes -pub fn mq_set_nonblock(mqd: &MqdT) -> Result<MqAttr> { - let oldattr = mq_getattr(mqd)?; - let newattr = MqAttr::new( - mq_attr_member_t::from(MQ_OFlag::O_NONBLOCK.bits()), - oldattr.mq_attr.mq_maxmsg, - oldattr.mq_attr.mq_msgsize, - oldattr.mq_attr.mq_curmsgs, - ); - mq_setattr(mqd, &newattr) -} - -/// Convenience function. -/// Removes `O_NONBLOCK` attribute for a given message queue descriptor -/// Returns the old attributes -pub fn mq_remove_nonblock(mqd: &MqdT) -> Result<MqAttr> { - let oldattr = mq_getattr(mqd)?; - let newattr = MqAttr::new( - 0, - oldattr.mq_attr.mq_maxmsg, - oldattr.mq_attr.mq_msgsize, - oldattr.mq_attr.mq_curmsgs, - ); - mq_setattr(mqd, &newattr) -} diff --git a/vendor/nix/src/net/if_.rs b/vendor/nix/src/net/if_.rs deleted file mode 100644 index b2423bc67..000000000 --- a/vendor/nix/src/net/if_.rs +++ /dev/null @@ -1,469 +0,0 @@ -//! Network interface name resolution. -//! -//! Uses Linux and/or POSIX functions to resolve interface names like "eth0" -//! or "socan1" into device numbers. - -use crate::{Error, NixPath, Result}; -use libc::c_uint; - -/// Resolve an interface into a interface number. -pub fn if_nametoindex<P: ?Sized + NixPath>(name: &P) -> Result<c_uint> { - let if_index = name - .with_nix_path(|name| unsafe { libc::if_nametoindex(name.as_ptr()) })?; - - if if_index == 0 { - Err(Error::last()) - } else { - Ok(if_index) - } -} - -libc_bitflags!( - /// Standard interface flags, used by `getifaddrs` - pub struct InterfaceFlags: libc::c_int { - /// Interface is running. (see - /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - IFF_UP; - /// Valid broadcast address set. (see - /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - IFF_BROADCAST; - /// Internal debugging flag. (see - /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - #[cfg(not(target_os = "haiku"))] - IFF_DEBUG; - /// Interface is a loopback interface. (see - /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - IFF_LOOPBACK; - /// Interface is a point-to-point link. (see - /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - IFF_POINTOPOINT; - /// Avoid use of trailers. (see - /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - #[cfg(any(target_os = "android", - target_os = "fuchsia", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "illumos", - target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_NOTRAILERS; - /// Interface manages own routes. - #[cfg(any(target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_SMART; - /// Resources allocated. (see - /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - #[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "illumos", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_RUNNING; - /// No arp protocol, L2 destination address not set. (see - /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - IFF_NOARP; - /// Interface is in promiscuous mode. (see - /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - IFF_PROMISC; - /// Receive all multicast packets. (see - /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - IFF_ALLMULTI; - /// Master of a load balancing bundle. (see - /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_MASTER; - /// transmission in progress, tx hardware queue is full - #[cfg(any(target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "ios"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_OACTIVE; - /// Protocol code on board. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_INTELLIGENT; - /// Slave of a load balancing bundle. (see - /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_SLAVE; - /// Can't hear own transmissions. - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_SIMPLEX; - /// Supports multicast. (see - /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - IFF_MULTICAST; - /// Per link layer defined bit. - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "ios"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_LINK0; - /// Multicast using broadcast. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_MULTI_BCAST; - /// Is able to select media type via ifmap. (see - /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_PORTSEL; - /// Per link layer defined bit. - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "ios"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_LINK1; - /// Non-unique address. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_UNNUMBERED; - /// Auto media selection active. (see - /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_AUTOMEDIA; - /// Per link layer defined bit. - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "ios"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_LINK2; - /// Use alternate physical connection. - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "ios"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_ALTPHYS; - /// DHCP controls interface. - #[cfg(any(target_os = "solaris", target_os = "illumos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_DHCPRUNNING; - /// The addresses are lost when the interface goes down. (see - /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_DYNAMIC; - /// Do not advertise. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_PRIVATE; - /// Driver signals L1 up. Volatile. - #[cfg(any(target_os = "fuchsia", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_LOWER_UP; - /// Interface is in polling mode. - #[cfg(any(target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_POLLING_COMPAT; - /// Unconfigurable using ioctl(2). - #[cfg(any(target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_CANTCONFIG; - /// Do not transmit packets. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_NOXMIT; - /// Driver signals dormant. Volatile. - #[cfg(any(target_os = "fuchsia", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_DORMANT; - /// User-requested promisc mode. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_PPROMISC; - /// Just on-link subnet. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_NOLOCAL; - /// Echo sent packets. Volatile. - #[cfg(any(target_os = "fuchsia", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_ECHO; - /// User-requested monitor mode. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_MONITOR; - /// Address is deprecated. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_DEPRECATED; - /// Static ARP. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_STATICARP; - /// Address from stateless addrconf. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_ADDRCONF; - /// Interface is in polling mode. - #[cfg(any(target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_NPOLLING; - /// Router on interface. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_ROUTER; - /// Interface is in polling mode. - #[cfg(any(target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_IDIRECT; - /// Interface is winding down - #[cfg(any(target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_DYING; - /// No NUD on interface. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_NONUD; - /// Interface is being renamed - #[cfg(any(target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_RENAMING; - /// Anycast address. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_ANYCAST; - /// Don't exchange routing info. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_NORTEXCH; - /// Do not provide packet information - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_NO_PI as libc::c_int; - /// TUN device (no Ethernet headers) - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_TUN as libc::c_int; - /// TAP device - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_TAP as libc::c_int; - /// IPv4 interface. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_IPV4; - /// IPv6 interface. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_IPV6; - /// in.mpathd test address - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_NOFAILOVER; - /// Interface has failed - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_FAILED; - /// Interface is a hot-spare - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_STANDBY; - /// Functioning but not used - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_INACTIVE; - /// Interface is offline - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_OFFLINE; - #[cfg(target_os = "solaris")] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_COS_ENABLED; - /// Prefer as source addr. - #[cfg(target_os = "solaris")] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_PREFERRED; - /// RFC3041 - #[cfg(target_os = "solaris")] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_TEMPORARY; - /// MTU set with SIOCSLIFMTU - #[cfg(target_os = "solaris")] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_FIXEDMTU; - /// Cannot send / receive packets - #[cfg(target_os = "solaris")] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_VIRTUAL; - /// Local address in use - #[cfg(target_os = "solaris")] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_DUPLICATE; - /// IPMP IP interface - #[cfg(target_os = "solaris")] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_IPMP; - } -); - -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", -))] -#[cfg_attr(docsrs, doc(cfg(all())))] -mod if_nameindex { - use super::*; - - use std::ffi::CStr; - use std::fmt; - use std::marker::PhantomData; - use std::ptr::NonNull; - - /// A network interface. Has a name like "eth0" or "wlp4s0" or "wlan0", as well as an index - /// (1, 2, 3, etc) that identifies it in the OS's networking stack. - #[allow(missing_copy_implementations)] - #[repr(transparent)] - pub struct Interface(libc::if_nameindex); - - impl Interface { - /// Obtain the index of this interface. - pub fn index(&self) -> c_uint { - self.0.if_index - } - - /// Obtain the name of this interface. - pub fn name(&self) -> &CStr { - unsafe { CStr::from_ptr(self.0.if_name) } - } - } - - impl fmt::Debug for Interface { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Interface") - .field("index", &self.index()) - .field("name", &self.name()) - .finish() - } - } - - /// A list of the network interfaces available on this system. Obtained from [`if_nameindex()`]. - pub struct Interfaces { - ptr: NonNull<libc::if_nameindex>, - } - - impl Interfaces { - /// Iterate over the interfaces in this list. - #[inline] - pub fn iter(&self) -> InterfacesIter<'_> { - self.into_iter() - } - - /// Convert this to a slice of interfaces. Note that the underlying interfaces list is - /// null-terminated, so calling this calculates the length. If random access isn't needed, - /// [`Interfaces::iter()`] should be used instead. - pub fn to_slice(&self) -> &[Interface] { - let ifs = self.ptr.as_ptr() as *const Interface; - let len = self.iter().count(); - unsafe { std::slice::from_raw_parts(ifs, len) } - } - } - - impl Drop for Interfaces { - fn drop(&mut self) { - unsafe { libc::if_freenameindex(self.ptr.as_ptr()) }; - } - } - - impl fmt::Debug for Interfaces { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.to_slice().fmt(f) - } - } - - impl<'a> IntoIterator for &'a Interfaces { - type IntoIter = InterfacesIter<'a>; - type Item = &'a Interface; - #[inline] - fn into_iter(self) -> Self::IntoIter { - InterfacesIter { - ptr: self.ptr.as_ptr(), - _marker: PhantomData, - } - } - } - - /// An iterator over the interfaces in an [`Interfaces`]. - #[derive(Debug)] - pub struct InterfacesIter<'a> { - ptr: *const libc::if_nameindex, - _marker: PhantomData<&'a Interfaces>, - } - - impl<'a> Iterator for InterfacesIter<'a> { - type Item = &'a Interface; - #[inline] - fn next(&mut self) -> Option<Self::Item> { - unsafe { - if (*self.ptr).if_index == 0 { - None - } else { - let ret = &*(self.ptr as *const Interface); - self.ptr = self.ptr.add(1); - Some(ret) - } - } - } - } - - /// Retrieve a list of the network interfaces available on the local system. - /// - /// ``` - /// let interfaces = nix::net::if_::if_nameindex().unwrap(); - /// for iface in &interfaces { - /// println!("Interface #{} is called {}", iface.index(), iface.name().to_string_lossy()); - /// } - /// ``` - pub fn if_nameindex() -> Result<Interfaces> { - unsafe { - let ifs = libc::if_nameindex(); - let ptr = NonNull::new(ifs).ok_or_else(Error::last)?; - Ok(Interfaces { ptr }) - } - } -} -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", -))] -pub use if_nameindex::*; diff --git a/vendor/nix/src/net/mod.rs b/vendor/nix/src/net/mod.rs deleted file mode 100644 index 079fcfde6..000000000 --- a/vendor/nix/src/net/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -//! Functionality involving network interfaces -// To avoid clashing with the keyword "if", we use "if_" as the module name. -// The original header is called "net/if.h". -pub mod if_; diff --git a/vendor/nix/src/poll.rs b/vendor/nix/src/poll.rs deleted file mode 100644 index 6f227fee9..000000000 --- a/vendor/nix/src/poll.rs +++ /dev/null @@ -1,197 +0,0 @@ -//! Wait for events to trigger on specific file descriptors -use std::os::unix::io::{AsRawFd, RawFd}; - -use crate::errno::Errno; -use crate::Result; - -/// This is a wrapper around `libc::pollfd`. -/// -/// It's meant to be used as an argument to the [`poll`](fn.poll.html) and -/// [`ppoll`](fn.ppoll.html) functions to specify the events of interest -/// for a specific file descriptor. -/// -/// After a call to `poll` or `ppoll`, the events that occurred can be -/// retrieved by calling [`revents()`](#method.revents) on the `PollFd`. -#[repr(transparent)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct PollFd { - pollfd: libc::pollfd, -} - -impl PollFd { - /// Creates a new `PollFd` specifying the events of interest - /// for a given file descriptor. - pub const fn new(fd: RawFd, events: PollFlags) -> PollFd { - PollFd { - pollfd: libc::pollfd { - fd, - events: events.bits(), - revents: PollFlags::empty().bits(), - }, - } - } - - /// Returns the events that occurred in the last call to `poll` or `ppoll`. Will only return - /// `None` if the kernel provides status flags that Nix does not know about. - pub fn revents(self) -> Option<PollFlags> { - PollFlags::from_bits(self.pollfd.revents) - } - - /// Returns if any of the events of interest occured in the last call to `poll` or `ppoll`. Will - /// only return `None` if the kernel provides status flags that Nix does not know about. - /// - /// Equivalent to `x.revents()? != PollFlags::empty()`. - /// - /// This is marginally more efficient than [`PollFd::all`]. - pub fn any(self) -> Option<bool> { - Some(self.revents()? != PollFlags::empty()) - } - - /// Returns if all the events of interest occured in the last call to `poll` or `ppoll`. Will - /// only return `None` if the kernel provides status flags that Nix does not know about. - /// - /// Equivalent to `x.revents()? & x.events() == x.events()`. - /// - /// This is marginally less efficient than [`PollFd::any`]. - pub fn all(self) -> Option<bool> { - Some(self.revents()? & self.events() == self.events()) - } - - /// The events of interest for this `PollFd`. - pub fn events(self) -> PollFlags { - PollFlags::from_bits(self.pollfd.events).unwrap() - } - - /// Modify the events of interest for this `PollFd`. - pub fn set_events(&mut self, events: PollFlags) { - self.pollfd.events = events.bits(); - } -} - -impl AsRawFd for PollFd { - fn as_raw_fd(&self) -> RawFd { - self.pollfd.fd - } -} - -libc_bitflags! { - /// These flags define the different events that can be monitored by `poll` and `ppoll` - pub struct PollFlags: libc::c_short { - /// There is data to read. - POLLIN; - /// There is some exceptional condition on the file descriptor. - /// - /// Possibilities include: - /// - /// * There is out-of-band data on a TCP socket (see - /// [tcp(7)](https://man7.org/linux/man-pages/man7/tcp.7.html)). - /// * A pseudoterminal master in packet mode has seen a state - /// change on the slave (see - /// [ioctl_tty(2)](https://man7.org/linux/man-pages/man2/ioctl_tty.2.html)). - /// * A cgroup.events file has been modified (see - /// [cgroups(7)](https://man7.org/linux/man-pages/man7/cgroups.7.html)). - POLLPRI; - /// Writing is now possible, though a write larger that the - /// available space in a socket or pipe will still block (unless - /// `O_NONBLOCK` is set). - POLLOUT; - /// Equivalent to [`POLLIN`](constant.POLLIN.html) - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - POLLRDNORM; - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// Equivalent to [`POLLOUT`](constant.POLLOUT.html) - POLLWRNORM; - /// Priority band data can be read (generally unused on Linux). - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - POLLRDBAND; - /// Priority data may be written. - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - POLLWRBAND; - /// Error condition (only returned in - /// [`PollFd::revents`](struct.PollFd.html#method.revents); - /// ignored in [`PollFd::new`](struct.PollFd.html#method.new)). - /// This bit is also set for a file descriptor referring to the - /// write end of a pipe when the read end has been closed. - POLLERR; - /// Hang up (only returned in [`PollFd::revents`](struct.PollFd.html#method.revents); - /// ignored in [`PollFd::new`](struct.PollFd.html#method.new)). - /// Note that when reading from a channel such as a pipe or a stream - /// socket, this event merely indicates that the peer closed its - /// end of the channel. Subsequent reads from the channel will - /// return 0 (end of file) only after all outstanding data in the - /// channel has been consumed. - POLLHUP; - /// Invalid request: `fd` not open (only returned in - /// [`PollFd::revents`](struct.PollFd.html#method.revents); - /// ignored in [`PollFd::new`](struct.PollFd.html#method.new)). - POLLNVAL; - } -} - -/// `poll` waits for one of a set of file descriptors to become ready to perform I/O. -/// ([`poll(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html)) -/// -/// `fds` contains all [`PollFd`](struct.PollFd.html) to poll. -/// The function will return as soon as any event occur for any of these `PollFd`s. -/// -/// The `timeout` argument specifies the number of milliseconds that `poll()` -/// should block waiting for a file descriptor to become ready. The call -/// will block until either: -/// -/// * a file descriptor becomes ready; -/// * the call is interrupted by a signal handler; or -/// * the timeout expires. -/// -/// Note that the timeout interval will be rounded up to the system clock -/// granularity, and kernel scheduling delays mean that the blocking -/// interval may overrun by a small amount. Specifying a negative value -/// in timeout means an infinite timeout. Specifying a timeout of zero -/// causes `poll()` to return immediately, even if no file descriptors are -/// ready. -pub fn poll(fds: &mut [PollFd], timeout: libc::c_int) -> Result<libc::c_int> { - let res = unsafe { - libc::poll( - fds.as_mut_ptr() as *mut libc::pollfd, - fds.len() as libc::nfds_t, - timeout, - ) - }; - - Errno::result(res) -} - -feature! { -#![feature = "signal"] -/// `ppoll()` allows an application to safely wait until either a file -/// descriptor becomes ready or until a signal is caught. -/// ([`poll(2)`](https://man7.org/linux/man-pages/man2/poll.2.html)) -/// -/// `ppoll` behaves like `poll`, but let you specify what signals may interrupt it -/// with the `sigmask` argument. If you want `ppoll` to block indefinitely, -/// specify `None` as `timeout` (it is like `timeout = -1` for `poll`). -/// If `sigmask` is `None`, then no signal mask manipulation is performed, -/// so in that case `ppoll` differs from `poll` only in the precision of the -/// timeout argument. -/// -#[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))] -pub fn ppoll( - fds: &mut [PollFd], - timeout: Option<crate::sys::time::TimeSpec>, - sigmask: Option<crate::sys::signal::SigSet> - ) -> Result<libc::c_int> -{ - let timeout = timeout.as_ref().map_or(core::ptr::null(), |r| r.as_ref()); - let sigmask = sigmask.as_ref().map_or(core::ptr::null(), |r| r.as_ref()); - let res = unsafe { - libc::ppoll(fds.as_mut_ptr() as *mut libc::pollfd, - fds.len() as libc::nfds_t, - timeout, - sigmask) - }; - Errno::result(res) -} -} diff --git a/vendor/nix/src/pty.rs b/vendor/nix/src/pty.rs deleted file mode 100644 index 28ae5e924..000000000 --- a/vendor/nix/src/pty.rs +++ /dev/null @@ -1,371 +0,0 @@ -//! Create master and slave virtual pseudo-terminals (PTYs) - -pub use libc::pid_t as SessionId; -pub use libc::winsize as Winsize; - -use std::ffi::CStr; -use std::io; -use std::mem; -use std::os::unix::prelude::*; - -use crate::errno::Errno; -use crate::sys::termios::Termios; -#[cfg(feature = "process")] -use crate::unistd::{ForkResult, Pid}; -use crate::{fcntl, unistd, Result}; - -/// Representation of a master/slave pty pair -/// -/// This is returned by `openpty`. Note that this type does *not* implement `Drop`, so the user -/// must manually close the file descriptors. -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct OpenptyResult { - /// The master port in a virtual pty pair - pub master: RawFd, - /// The slave port in a virtual pty pair - pub slave: RawFd, -} - -feature! { -#![feature = "process"] -/// Representation of a master with a forked pty -/// -/// This is returned by `forkpty`. Note that this type does *not* implement `Drop`, so the user -/// must manually close the file descriptors. -#[derive(Clone, Copy, Debug)] -pub struct ForkptyResult { - /// The master port in a virtual pty pair - pub master: RawFd, - /// Metadata about forked process - pub fork_result: ForkResult, -} -} - -/// Representation of the Master device in a master/slave pty pair -/// -/// While this datatype is a thin wrapper around `RawFd`, it enforces that the available PTY -/// functions are given the correct file descriptor. Additionally this type implements `Drop`, -/// so that when it's consumed or goes out of scope, it's automatically cleaned-up. -#[derive(Debug, Eq, Hash, PartialEq)] -pub struct PtyMaster(RawFd); - -impl AsRawFd for PtyMaster { - fn as_raw_fd(&self) -> RawFd { - self.0 - } -} - -impl IntoRawFd for PtyMaster { - fn into_raw_fd(self) -> RawFd { - let fd = self.0; - mem::forget(self); - fd - } -} - -impl Drop for PtyMaster { - fn drop(&mut self) { - // On drop, we ignore errors like EINTR and EIO because there's no clear - // way to handle them, we can't return anything, and (on FreeBSD at - // least) the file descriptor is deallocated in these cases. However, - // we must panic on EBADF, because it is always an error to close an - // invalid file descriptor. That frequently indicates a double-close - // condition, which can cause confusing errors for future I/O - // operations. - let e = unistd::close(self.0); - if e == Err(Errno::EBADF) { - panic!("Closing an invalid file descriptor!"); - }; - } -} - -impl io::Read for PtyMaster { - fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { - unistd::read(self.0, buf).map_err(io::Error::from) - } -} - -impl io::Write for PtyMaster { - fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - unistd::write(self.0, buf).map_err(io::Error::from) - } - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -impl io::Read for &PtyMaster { - fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { - unistd::read(self.0, buf).map_err(io::Error::from) - } -} - -impl io::Write for &PtyMaster { - fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - unistd::write(self.0, buf).map_err(io::Error::from) - } - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -/// Grant access to a slave pseudoterminal (see -/// [`grantpt(3)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/grantpt.html)) -/// -/// `grantpt()` changes the mode and owner of the slave pseudoterminal device corresponding to the -/// master pseudoterminal referred to by `fd`. This is a necessary step towards opening the slave. -#[inline] -pub fn grantpt(fd: &PtyMaster) -> Result<()> { - if unsafe { libc::grantpt(fd.as_raw_fd()) } < 0 { - return Err(Errno::last()); - } - - Ok(()) -} - -/// Open a pseudoterminal device (see -/// [`posix_openpt(3)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_openpt.html)) -/// -/// `posix_openpt()` returns a file descriptor to an existing unused pseudoterminal master device. -/// -/// # Examples -/// -/// A common use case with this function is to open both a master and slave PTY pair. This can be -/// done as follows: -/// -/// ``` -/// use std::path::Path; -/// use nix::fcntl::{OFlag, open}; -/// use nix::pty::{grantpt, posix_openpt, ptsname, unlockpt}; -/// use nix::sys::stat::Mode; -/// -/// # #[allow(dead_code)] -/// # fn run() -> nix::Result<()> { -/// // Open a new PTY master -/// let master_fd = posix_openpt(OFlag::O_RDWR)?; -/// -/// // Allow a slave to be generated for it -/// grantpt(&master_fd)?; -/// unlockpt(&master_fd)?; -/// -/// // Get the name of the slave -/// let slave_name = unsafe { ptsname(&master_fd) }?; -/// -/// // Try to open the slave -/// let _slave_fd = open(Path::new(&slave_name), OFlag::O_RDWR, Mode::empty())?; -/// # Ok(()) -/// # } -/// ``` -#[inline] -pub fn posix_openpt(flags: fcntl::OFlag) -> Result<PtyMaster> { - let fd = unsafe { libc::posix_openpt(flags.bits()) }; - - if fd < 0 { - return Err(Errno::last()); - } - - Ok(PtyMaster(fd)) -} - -/// Get the name of the slave pseudoterminal (see -/// [`ptsname(3)`](https://man7.org/linux/man-pages/man3/ptsname.3.html)) -/// -/// `ptsname()` returns the name of the slave pseudoterminal device corresponding to the master -/// referred to by `fd`. -/// -/// This value is useful for opening the slave pty once the master has already been opened with -/// `posix_openpt()`. -/// -/// # Safety -/// -/// `ptsname()` mutates global variables and is *not* threadsafe. -/// Mutating global variables is always considered `unsafe` by Rust and this -/// function is marked as `unsafe` to reflect that. -/// -/// For a threadsafe and non-`unsafe` alternative on Linux, see `ptsname_r()`. -#[inline] -pub unsafe fn ptsname(fd: &PtyMaster) -> Result<String> { - let name_ptr = libc::ptsname(fd.as_raw_fd()); - if name_ptr.is_null() { - return Err(Errno::last()); - } - - let name = CStr::from_ptr(name_ptr); - Ok(name.to_string_lossy().into_owned()) -} - -/// Get the name of the slave pseudoterminal (see -/// [`ptsname(3)`](https://man7.org/linux/man-pages/man3/ptsname.3.html)) -/// -/// `ptsname_r()` returns the name of the slave pseudoterminal device corresponding to the master -/// referred to by `fd`. This is the threadsafe version of `ptsname()`, but it is not part of the -/// POSIX standard and is instead a Linux-specific extension. -/// -/// This value is useful for opening the slave ptty once the master has already been opened with -/// `posix_openpt()`. -#[cfg(any(target_os = "android", target_os = "linux"))] -#[cfg_attr(docsrs, doc(cfg(all())))] -#[inline] -pub fn ptsname_r(fd: &PtyMaster) -> Result<String> { - let mut name_buf = Vec::<libc::c_char>::with_capacity(64); - let name_buf_ptr = name_buf.as_mut_ptr(); - let cname = unsafe { - let cap = name_buf.capacity(); - if libc::ptsname_r(fd.as_raw_fd(), name_buf_ptr, cap) != 0 { - return Err(crate::Error::last()); - } - CStr::from_ptr(name_buf.as_ptr()) - }; - - let name = cname.to_string_lossy().into_owned(); - Ok(name) -} - -/// Unlock a pseudoterminal master/slave pseudoterminal pair (see -/// [`unlockpt(3)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlockpt.html)) -/// -/// `unlockpt()` unlocks the slave pseudoterminal device corresponding to the master pseudoterminal -/// referred to by `fd`. This must be called before trying to open the slave side of a -/// pseudoterminal. -#[inline] -pub fn unlockpt(fd: &PtyMaster) -> Result<()> { - if unsafe { libc::unlockpt(fd.as_raw_fd()) } < 0 { - return Err(Errno::last()); - } - - Ok(()) -} - -/// Create a new pseudoterminal, returning the slave and master file descriptors -/// in `OpenptyResult` -/// (see [`openpty`](https://man7.org/linux/man-pages/man3/openpty.3.html)). -/// -/// If `winsize` is not `None`, the window size of the slave will be set to -/// the values in `winsize`. If `termios` is not `None`, the pseudoterminal's -/// terminal settings of the slave will be set to the values in `termios`. -#[inline] -pub fn openpty< - 'a, - 'b, - T: Into<Option<&'a Winsize>>, - U: Into<Option<&'b Termios>>, ->( - winsize: T, - termios: U, -) -> Result<OpenptyResult> { - use std::ptr; - - let mut slave = mem::MaybeUninit::<libc::c_int>::uninit(); - let mut master = mem::MaybeUninit::<libc::c_int>::uninit(); - let ret = { - match (termios.into(), winsize.into()) { - (Some(termios), Some(winsize)) => { - let inner_termios = termios.get_libc_termios(); - unsafe { - libc::openpty( - master.as_mut_ptr(), - slave.as_mut_ptr(), - ptr::null_mut(), - &*inner_termios as *const libc::termios as *mut _, - winsize as *const Winsize as *mut _, - ) - } - } - (None, Some(winsize)) => unsafe { - libc::openpty( - master.as_mut_ptr(), - slave.as_mut_ptr(), - ptr::null_mut(), - ptr::null_mut(), - winsize as *const Winsize as *mut _, - ) - }, - (Some(termios), None) => { - let inner_termios = termios.get_libc_termios(); - unsafe { - libc::openpty( - master.as_mut_ptr(), - slave.as_mut_ptr(), - ptr::null_mut(), - &*inner_termios as *const libc::termios as *mut _, - ptr::null_mut(), - ) - } - } - (None, None) => unsafe { - libc::openpty( - master.as_mut_ptr(), - slave.as_mut_ptr(), - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - ) - }, - } - }; - - Errno::result(ret)?; - - unsafe { - Ok(OpenptyResult { - master: master.assume_init(), - slave: slave.assume_init(), - }) - } -} - -feature! { -#![feature = "process"] -/// Create a new pseudoterminal, returning the master file descriptor and forked pid. -/// in `ForkptyResult` -/// (see [`forkpty`](https://man7.org/linux/man-pages/man3/forkpty.3.html)). -/// -/// If `winsize` is not `None`, the window size of the slave will be set to -/// the values in `winsize`. If `termios` is not `None`, the pseudoterminal's -/// terminal settings of the slave will be set to the values in `termios`. -/// -/// # Safety -/// -/// In a multithreaded program, only [async-signal-safe] functions like `pause` -/// and `_exit` may be called by the child (the parent isn't restricted). Note -/// that memory allocation may **not** be async-signal-safe and thus must be -/// prevented. -/// -/// Those functions are only a small subset of your operating system's API, so -/// special care must be taken to only invoke code you can control and audit. -/// -/// [async-signal-safe]: https://man7.org/linux/man-pages/man7/signal-safety.7.html -pub unsafe fn forkpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b Termios>>>( - winsize: T, - termios: U, -) -> Result<ForkptyResult> { - use std::ptr; - - let mut master = mem::MaybeUninit::<libc::c_int>::uninit(); - - let term = match termios.into() { - Some(termios) => { - let inner_termios = termios.get_libc_termios(); - &*inner_termios as *const libc::termios as *mut _ - }, - None => ptr::null_mut(), - }; - - let win = winsize - .into() - .map(|ws| ws as *const Winsize as *mut _) - .unwrap_or(ptr::null_mut()); - - let res = libc::forkpty(master.as_mut_ptr(), ptr::null_mut(), term, win); - - let fork_result = Errno::result(res).map(|res| match res { - 0 => ForkResult::Child, - res => ForkResult::Parent { child: Pid::from_raw(res) }, - })?; - - Ok(ForkptyResult { - master: master.assume_init(), - fork_result, - }) -} -} diff --git a/vendor/nix/src/sched.rs b/vendor/nix/src/sched.rs deleted file mode 100644 index d5b1233cf..000000000 --- a/vendor/nix/src/sched.rs +++ /dev/null @@ -1,324 +0,0 @@ -//! Execution scheduling -//! -//! See Also -//! [sched.h](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sched.h.html) -use crate::{Errno, Result}; - -#[cfg(any(target_os = "android", target_os = "linux"))] -pub use self::sched_linux_like::*; - -#[cfg(any(target_os = "android", target_os = "linux"))] -#[cfg_attr(docsrs, doc(cfg(all())))] -mod sched_linux_like { - use crate::errno::Errno; - use crate::unistd::Pid; - use crate::Result; - use libc::{self, c_int, c_void}; - use std::mem; - use std::option::Option; - use std::os::unix::io::RawFd; - - // For some functions taking with a parameter of type CloneFlags, - // only a subset of these flags have an effect. - libc_bitflags! { - /// Options for use with [`clone`] - pub struct CloneFlags: c_int { - /// The calling process and the child process run in the same - /// memory space. - CLONE_VM; - /// The caller and the child process share the same filesystem - /// information. - CLONE_FS; - /// The calling process and the child process share the same file - /// descriptor table. - CLONE_FILES; - /// The calling process and the child process share the same table - /// of signal handlers. - CLONE_SIGHAND; - /// If the calling process is being traced, then trace the child - /// also. - CLONE_PTRACE; - /// The execution of the calling process is suspended until the - /// child releases its virtual memory resources via a call to - /// execve(2) or _exit(2) (as with vfork(2)). - CLONE_VFORK; - /// The parent of the new child (as returned by getppid(2)) - /// will be the same as that of the calling process. - CLONE_PARENT; - /// The child is placed in the same thread group as the calling - /// process. - CLONE_THREAD; - /// The cloned child is started in a new mount namespace. - CLONE_NEWNS; - /// The child and the calling process share a single list of System - /// V semaphore adjustment values - CLONE_SYSVSEM; - // Not supported by Nix due to lack of varargs support in Rust FFI - // CLONE_SETTLS; - // Not supported by Nix due to lack of varargs support in Rust FFI - // CLONE_PARENT_SETTID; - // Not supported by Nix due to lack of varargs support in Rust FFI - // CLONE_CHILD_CLEARTID; - /// Unused since Linux 2.6.2 - #[deprecated(since = "0.23.0", note = "Deprecated by Linux 2.6.2")] - CLONE_DETACHED; - /// A tracing process cannot force `CLONE_PTRACE` on this child - /// process. - CLONE_UNTRACED; - // Not supported by Nix due to lack of varargs support in Rust FFI - // CLONE_CHILD_SETTID; - /// Create the process in a new cgroup namespace. - CLONE_NEWCGROUP; - /// Create the process in a new UTS namespace. - CLONE_NEWUTS; - /// Create the process in a new IPC namespace. - CLONE_NEWIPC; - /// Create the process in a new user namespace. - CLONE_NEWUSER; - /// Create the process in a new PID namespace. - CLONE_NEWPID; - /// Create the process in a new network namespace. - CLONE_NEWNET; - /// The new process shares an I/O context with the calling process. - CLONE_IO; - } - } - - /// Type for the function executed by [`clone`]. - pub type CloneCb<'a> = Box<dyn FnMut() -> isize + 'a>; - - /// `clone` create a child process - /// ([`clone(2)`](https://man7.org/linux/man-pages/man2/clone.2.html)) - /// - /// `stack` is a reference to an array which will hold the stack of the new - /// process. Unlike when calling `clone(2)` from C, the provided stack - /// address need not be the highest address of the region. Nix will take - /// care of that requirement. The user only needs to provide a reference to - /// a normally allocated buffer. - pub fn clone( - mut cb: CloneCb, - stack: &mut [u8], - flags: CloneFlags, - signal: Option<c_int>, - ) -> Result<Pid> { - extern "C" fn callback(data: *mut CloneCb) -> c_int { - let cb: &mut CloneCb = unsafe { &mut *data }; - (*cb)() as c_int - } - - let res = unsafe { - let combined = flags.bits() | signal.unwrap_or(0); - let ptr = stack.as_mut_ptr().add(stack.len()); - let ptr_aligned = ptr.sub(ptr as usize % 16); - libc::clone( - mem::transmute( - callback - as extern "C" fn(*mut Box<dyn FnMut() -> isize>) -> i32, - ), - ptr_aligned as *mut c_void, - combined, - &mut cb as *mut _ as *mut c_void, - ) - }; - - Errno::result(res).map(Pid::from_raw) - } - - /// disassociate parts of the process execution context - /// - /// See also [unshare(2)](https://man7.org/linux/man-pages/man2/unshare.2.html) - pub fn unshare(flags: CloneFlags) -> Result<()> { - let res = unsafe { libc::unshare(flags.bits()) }; - - Errno::result(res).map(drop) - } - - /// reassociate thread with a namespace - /// - /// See also [setns(2)](https://man7.org/linux/man-pages/man2/setns.2.html) - pub fn setns(fd: RawFd, nstype: CloneFlags) -> Result<()> { - let res = unsafe { libc::setns(fd, nstype.bits()) }; - - Errno::result(res).map(drop) - } -} - -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux" -))] -pub use self::sched_affinity::*; - -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux" -))] -mod sched_affinity { - use crate::errno::Errno; - use crate::unistd::Pid; - use crate::Result; - use std::mem; - - /// CpuSet represent a bit-mask of CPUs. - /// CpuSets are used by sched_setaffinity and - /// sched_getaffinity for example. - /// - /// This is a wrapper around `libc::cpu_set_t`. - #[repr(transparent)] - #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] - pub struct CpuSet { - #[cfg(not(target_os = "freebsd"))] - cpu_set: libc::cpu_set_t, - #[cfg(target_os = "freebsd")] - cpu_set: libc::cpuset_t, - } - - impl CpuSet { - /// Create a new and empty CpuSet. - pub fn new() -> CpuSet { - CpuSet { - cpu_set: unsafe { mem::zeroed() }, - } - } - - /// Test to see if a CPU is in the CpuSet. - /// `field` is the CPU id to test - pub fn is_set(&self, field: usize) -> Result<bool> { - if field >= CpuSet::count() { - Err(Errno::EINVAL) - } else { - Ok(unsafe { libc::CPU_ISSET(field, &self.cpu_set) }) - } - } - - /// Add a CPU to CpuSet. - /// `field` is the CPU id to add - pub fn set(&mut self, field: usize) -> Result<()> { - if field >= CpuSet::count() { - Err(Errno::EINVAL) - } else { - unsafe { - libc::CPU_SET(field, &mut self.cpu_set); - } - Ok(()) - } - } - - /// Remove a CPU from CpuSet. - /// `field` is the CPU id to remove - pub fn unset(&mut self, field: usize) -> Result<()> { - if field >= CpuSet::count() { - Err(Errno::EINVAL) - } else { - unsafe { - libc::CPU_CLR(field, &mut self.cpu_set); - } - Ok(()) - } - } - - /// Return the maximum number of CPU in CpuSet - pub const fn count() -> usize { - #[cfg(not(target_os = "freebsd"))] - let bytes = mem::size_of::<libc::cpu_set_t>(); - #[cfg(target_os = "freebsd")] - let bytes = mem::size_of::<libc::cpuset_t>(); - - 8 * bytes - } - } - - impl Default for CpuSet { - fn default() -> Self { - Self::new() - } - } - - /// `sched_setaffinity` set a thread's CPU affinity mask - /// ([`sched_setaffinity(2)`](https://man7.org/linux/man-pages/man2/sched_setaffinity.2.html)) - /// - /// `pid` is the thread ID to update. - /// If pid is zero, then the calling thread is updated. - /// - /// The `cpuset` argument specifies the set of CPUs on which the thread - /// will be eligible to run. - /// - /// # Example - /// - /// Binding the current thread to CPU 0 can be done as follows: - /// - /// ```rust,no_run - /// use nix::sched::{CpuSet, sched_setaffinity}; - /// use nix::unistd::Pid; - /// - /// let mut cpu_set = CpuSet::new(); - /// cpu_set.set(0).unwrap(); - /// sched_setaffinity(Pid::from_raw(0), &cpu_set).unwrap(); - /// ``` - pub fn sched_setaffinity(pid: Pid, cpuset: &CpuSet) -> Result<()> { - let res = unsafe { - libc::sched_setaffinity( - pid.into(), - mem::size_of::<CpuSet>() as libc::size_t, - &cpuset.cpu_set, - ) - }; - - Errno::result(res).map(drop) - } - - /// `sched_getaffinity` get a thread's CPU affinity mask - /// ([`sched_getaffinity(2)`](https://man7.org/linux/man-pages/man2/sched_getaffinity.2.html)) - /// - /// `pid` is the thread ID to check. - /// If pid is zero, then the calling thread is checked. - /// - /// Returned `cpuset` is the set of CPUs on which the thread - /// is eligible to run. - /// - /// # Example - /// - /// Checking if the current thread can run on CPU 0 can be done as follows: - /// - /// ```rust,no_run - /// use nix::sched::sched_getaffinity; - /// use nix::unistd::Pid; - /// - /// let cpu_set = sched_getaffinity(Pid::from_raw(0)).unwrap(); - /// if cpu_set.is_set(0).unwrap() { - /// println!("Current thread can run on CPU 0"); - /// } - /// ``` - pub fn sched_getaffinity(pid: Pid) -> Result<CpuSet> { - let mut cpuset = CpuSet::new(); - let res = unsafe { - libc::sched_getaffinity( - pid.into(), - mem::size_of::<CpuSet>() as libc::size_t, - &mut cpuset.cpu_set, - ) - }; - - Errno::result(res).and(Ok(cpuset)) - } - - /// Determines the CPU on which the calling thread is running. - pub fn sched_getcpu() -> Result<usize> { - let res = unsafe { libc::sched_getcpu() }; - - Errno::result(res).map(|int| int as usize) - } -} - -/// Explicitly yield the processor to other threads. -/// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_yield.html) -pub fn sched_yield() -> Result<()> { - let res = unsafe { libc::sched_yield() }; - - Errno::result(res).map(drop) -} diff --git a/vendor/nix/src/sys/aio.rs b/vendor/nix/src/sys/aio.rs deleted file mode 100644 index e2ce19b79..000000000 --- a/vendor/nix/src/sys/aio.rs +++ /dev/null @@ -1,1241 +0,0 @@ -// vim: tw=80 -//! POSIX Asynchronous I/O -//! -//! The POSIX AIO interface is used for asynchronous I/O on files and disk-like -//! devices. It supports [`read`](struct.AioRead.html#method.new), -//! [`write`](struct.AioWrite.html#method.new), -//! [`fsync`](struct.AioFsync.html#method.new), -//! [`readv`](struct.AioReadv.html#method.new), and -//! [`writev`](struct.AioWritev.html#method.new), operations, subject to -//! platform support. Completion -//! notifications can optionally be delivered via -//! [signals](../signal/enum.SigevNotify.html#variant.SigevSignal), via the -//! [`aio_suspend`](fn.aio_suspend.html) function, or via polling. Some -//! platforms support other completion -//! notifications, such as -//! [kevent](../signal/enum.SigevNotify.html#variant.SigevKevent). -//! -//! Multiple operations may be submitted in a batch with -//! [`lio_listio`](fn.lio_listio.html), though the standard does not guarantee -//! that they will be executed atomically. -//! -//! Outstanding operations may be cancelled with -//! [`cancel`](trait.Aio.html#method.cancel) or -//! [`aio_cancel_all`](fn.aio_cancel_all.html), though the operating system may -//! not support this for all filesystems and devices. -#[cfg(target_os = "freebsd")] -use std::io::{IoSlice, IoSliceMut}; -use std::{ - convert::TryFrom, - fmt::{self, Debug}, - marker::{PhantomData, PhantomPinned}, - mem, - os::unix::io::RawFd, - pin::Pin, - ptr, thread, -}; - -use libc::{c_void, off_t}; -use pin_utils::unsafe_pinned; - -use crate::{ - errno::Errno, - sys::{signal::*, time::TimeSpec}, - Result, -}; - -libc_enum! { - /// Mode for `AioCb::fsync`. Controls whether only data or both data and - /// metadata are synced. - #[repr(i32)] - #[non_exhaustive] - pub enum AioFsyncMode { - /// do it like `fsync` - O_SYNC, - /// on supported operating systems only, do it like `fdatasync` - #[cfg(any(target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - O_DSYNC - } - impl TryFrom<i32> -} - -libc_enum! { - /// Mode for [`lio_listio`](fn.lio_listio.html) - #[repr(i32)] - pub enum LioMode { - /// Requests that [`lio_listio`](fn.lio_listio.html) block until all - /// requested operations have been completed - LIO_WAIT, - /// Requests that [`lio_listio`](fn.lio_listio.html) return immediately - LIO_NOWAIT, - } -} - -/// Return values for [`AioCb::cancel`](struct.AioCb.html#method.cancel) and -/// [`aio_cancel_all`](fn.aio_cancel_all.html) -#[repr(i32)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum AioCancelStat { - /// All outstanding requests were canceled - AioCanceled = libc::AIO_CANCELED, - /// Some requests were not canceled. Their status should be checked with - /// `AioCb::error` - AioNotCanceled = libc::AIO_NOTCANCELED, - /// All of the requests have already finished - AioAllDone = libc::AIO_ALLDONE, -} - -/// Newtype that adds Send and Sync to libc::aiocb, which contains raw pointers -#[repr(transparent)] -struct LibcAiocb(libc::aiocb); - -unsafe impl Send for LibcAiocb {} -unsafe impl Sync for LibcAiocb {} - -/// Base class for all AIO operations. Should only be used directly when -/// checking for completion. -// We could create some kind of AsPinnedMut trait, and implement it for all aio -// ops, allowing the crate's users to get pinned references to `AioCb`. That -// could save some code for things like polling methods. But IMHO it would -// provide polymorphism at the wrong level. Instead, the best place for -// polymorphism is at the level of `Futures`. -#[repr(C)] -struct AioCb { - aiocb: LibcAiocb, - /// Could this `AioCb` potentially have any in-kernel state? - // It would be really nice to perform the in-progress check entirely at - // compile time. But I can't figure out how, because: - // * Future::poll takes a `Pin<&mut self>` rather than `self`, and - // * Rust's lack of an equivalent of C++'s Guaranteed Copy Elision means - // that there's no way to write an AioCb constructor that neither boxes - // the object itself, nor moves it during return. - in_progress: bool, -} - -impl AioCb { - pin_utils::unsafe_unpinned!(aiocb: LibcAiocb); - - fn aio_return(mut self: Pin<&mut Self>) -> Result<usize> { - self.in_progress = false; - unsafe { - let p: *mut libc::aiocb = &mut self.aiocb.0; - Errno::result(libc::aio_return(p)) - } - .map(|r| r as usize) - } - - fn cancel(mut self: Pin<&mut Self>) -> Result<AioCancelStat> { - let r = unsafe { - libc::aio_cancel(self.aiocb.0.aio_fildes, &mut self.aiocb.0) - }; - match r { - libc::AIO_CANCELED => Ok(AioCancelStat::AioCanceled), - libc::AIO_NOTCANCELED => Ok(AioCancelStat::AioNotCanceled), - libc::AIO_ALLDONE => Ok(AioCancelStat::AioAllDone), - -1 => Err(Errno::last()), - _ => panic!("unknown aio_cancel return value"), - } - } - - fn common_init(fd: RawFd, prio: i32, sigev_notify: SigevNotify) -> Self { - // Use mem::zeroed instead of explicitly zeroing each field, because the - // number and name of reserved fields is OS-dependent. On some OSes, - // some reserved fields are used the kernel for state, and must be - // explicitly zeroed when allocated. - let mut a = unsafe { mem::zeroed::<libc::aiocb>() }; - a.aio_fildes = fd; - a.aio_reqprio = prio; - a.aio_sigevent = SigEvent::new(sigev_notify).sigevent(); - AioCb { - aiocb: LibcAiocb(a), - in_progress: false, - } - } - - fn error(self: Pin<&mut Self>) -> Result<()> { - let r = unsafe { libc::aio_error(&self.aiocb().0) }; - match r { - 0 => Ok(()), - num if num > 0 => Err(Errno::from_i32(num)), - -1 => Err(Errno::last()), - num => panic!("unknown aio_error return value {:?}", num), - } - } - - fn in_progress(&self) -> bool { - self.in_progress - } - - fn set_in_progress(mut self: Pin<&mut Self>) { - self.as_mut().in_progress = true; - } - - /// Update the notification settings for an existing AIO operation that has - /// not yet been submitted. - // Takes a normal reference rather than a pinned one because this method is - // normally called before the object needs to be pinned, that is, before - // it's been submitted to the kernel. - fn set_sigev_notify(&mut self, sigev_notify: SigevNotify) { - assert!( - !self.in_progress, - "Can't change notification settings for an in-progress operation" - ); - self.aiocb.0.aio_sigevent = SigEvent::new(sigev_notify).sigevent(); - } -} - -impl Debug for AioCb { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_struct("AioCb") - .field("aiocb", &self.aiocb.0) - .field("in_progress", &self.in_progress) - .finish() - } -} - -impl Drop for AioCb { - /// If the `AioCb` has no remaining state in the kernel, just drop it. - /// Otherwise, dropping constitutes a resource leak, which is an error - fn drop(&mut self) { - assert!( - thread::panicking() || !self.in_progress, - "Dropped an in-progress AioCb" - ); - } -} - -/// Methods common to all AIO operations -pub trait Aio { - /// The return type of [`Aio::aio_return`]. - type Output; - - /// Retrieve return status of an asynchronous operation. - /// - /// Should only be called once for each operation, after [`Aio::error`] - /// indicates that it has completed. The result is the same as for the - /// synchronous `read(2)`, `write(2)`, of `fsync(2)` functions. - /// - /// # References - /// - /// [aio_return](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_return.html) - fn aio_return(self: Pin<&mut Self>) -> Result<Self::Output>; - - /// Cancels an outstanding AIO request. - /// - /// The operating system is not required to implement cancellation for all - /// file and device types. Even if it does, there is no guarantee that the - /// operation has not already completed. So the caller must check the - /// result and handle operations that were not canceled or that have already - /// completed. - /// - /// # Examples - /// - /// Cancel an outstanding aio operation. Note that we must still call - /// `aio_return` to free resources, even though we don't care about the - /// result. - /// - /// ``` - /// # use nix::errno::Errno; - /// # use nix::Error; - /// # use nix::sys::aio::*; - /// # use nix::sys::signal::SigevNotify; - /// # use std::{thread, time}; - /// # use std::io::Write; - /// # use std::os::unix::io::AsRawFd; - /// # use tempfile::tempfile; - /// let wbuf = b"CDEF"; - /// let mut f = tempfile().unwrap(); - /// let mut aiocb = Box::pin(AioWrite::new(f.as_raw_fd(), - /// 2, //offset - /// &wbuf[..], - /// 0, //priority - /// SigevNotify::SigevNone)); - /// aiocb.as_mut().submit().unwrap(); - /// let cs = aiocb.as_mut().cancel().unwrap(); - /// if cs == AioCancelStat::AioNotCanceled { - /// while (aiocb.as_mut().error() == Err(Errno::EINPROGRESS)) { - /// thread::sleep(time::Duration::from_millis(10)); - /// } - /// } - /// // Must call `aio_return`, but ignore the result - /// let _ = aiocb.as_mut().aio_return(); - /// ``` - /// - /// # References - /// - /// [aio_cancel](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_cancel.html) - fn cancel(self: Pin<&mut Self>) -> Result<AioCancelStat>; - - /// Retrieve error status of an asynchronous operation. - /// - /// If the request has not yet completed, returns `EINPROGRESS`. Otherwise, - /// returns `Ok` or any other error. - /// - /// # Examples - /// - /// Issue an aio operation and use `error` to poll for completion. Polling - /// is an alternative to `aio_suspend`, used by most of the other examples. - /// - /// ``` - /// # use nix::errno::Errno; - /// # use nix::Error; - /// # use nix::sys::aio::*; - /// # use nix::sys::signal::SigevNotify; - /// # use std::{thread, time}; - /// # use std::os::unix::io::AsRawFd; - /// # use tempfile::tempfile; - /// const WBUF: &[u8] = b"abcdef123456"; - /// let mut f = tempfile().unwrap(); - /// let mut aiocb = Box::pin(AioWrite::new(f.as_raw_fd(), - /// 2, //offset - /// WBUF, - /// 0, //priority - /// SigevNotify::SigevNone)); - /// aiocb.as_mut().submit().unwrap(); - /// while (aiocb.as_mut().error() == Err(Errno::EINPROGRESS)) { - /// thread::sleep(time::Duration::from_millis(10)); - /// } - /// assert_eq!(aiocb.as_mut().aio_return().unwrap(), WBUF.len()); - /// ``` - /// - /// # References - /// - /// [aio_error](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_error.html) - fn error(self: Pin<&mut Self>) -> Result<()>; - - /// Returns the underlying file descriptor associated with the operation. - fn fd(&self) -> RawFd; - - /// Does this operation currently have any in-kernel state? - /// - /// Dropping an operation that does have in-kernel state constitutes a - /// resource leak. - /// - /// # Examples - /// - /// ``` - /// # use nix::errno::Errno; - /// # use nix::Error; - /// # use nix::sys::aio::*; - /// # use nix::sys::signal::SigevNotify::SigevNone; - /// # use std::{thread, time}; - /// # use std::os::unix::io::AsRawFd; - /// # use tempfile::tempfile; - /// let f = tempfile().unwrap(); - /// let mut aiof = Box::pin(AioFsync::new(f.as_raw_fd(), AioFsyncMode::O_SYNC, - /// 0, SigevNone)); - /// assert!(!aiof.as_mut().in_progress()); - /// aiof.as_mut().submit().expect("aio_fsync failed early"); - /// assert!(aiof.as_mut().in_progress()); - /// while (aiof.as_mut().error() == Err(Errno::EINPROGRESS)) { - /// thread::sleep(time::Duration::from_millis(10)); - /// } - /// aiof.as_mut().aio_return().expect("aio_fsync failed late"); - /// assert!(!aiof.as_mut().in_progress()); - /// ``` - fn in_progress(&self) -> bool; - - /// Returns the priority of the `AioCb` - fn priority(&self) -> i32; - - /// Update the notification settings for an existing AIO operation that has - /// not yet been submitted. - fn set_sigev_notify(&mut self, sev: SigevNotify); - - /// Returns the `SigEvent` that will be used for notification. - fn sigevent(&self) -> SigEvent; - - /// Actually start the I/O operation. - /// - /// After calling this method and until [`Aio::aio_return`] returns `Ok`, - /// the structure may not be moved in memory. - fn submit(self: Pin<&mut Self>) -> Result<()>; -} - -macro_rules! aio_methods { - () => { - fn cancel(self: Pin<&mut Self>) -> Result<AioCancelStat> { - self.aiocb().cancel() - } - - fn error(self: Pin<&mut Self>) -> Result<()> { - self.aiocb().error() - } - - fn fd(&self) -> RawFd { - self.aiocb.aiocb.0.aio_fildes - } - - fn in_progress(&self) -> bool { - self.aiocb.in_progress() - } - - fn priority(&self) -> i32 { - self.aiocb.aiocb.0.aio_reqprio - } - - fn set_sigev_notify(&mut self, sev: SigevNotify) { - self.aiocb.set_sigev_notify(sev) - } - - fn sigevent(&self) -> SigEvent { - SigEvent::from(&self.aiocb.aiocb.0.aio_sigevent) - } - }; - ($func:ident) => { - aio_methods!(); - - fn aio_return(self: Pin<&mut Self>) -> Result<<Self as Aio>::Output> { - self.aiocb().aio_return() - } - - fn submit(mut self: Pin<&mut Self>) -> Result<()> { - let p: *mut libc::aiocb = &mut self.as_mut().aiocb().aiocb.0; - Errno::result({ unsafe { libc::$func(p) } }).map(|_| { - self.aiocb().set_in_progress(); - }) - } - }; -} - -/// An asynchronous version of `fsync(2)`. -/// -/// # References -/// -/// [aio_fsync](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_fsync.html) -/// # Examples -/// -/// ``` -/// # use nix::errno::Errno; -/// # use nix::Error; -/// # use nix::sys::aio::*; -/// # use nix::sys::signal::SigevNotify::SigevNone; -/// # use std::{thread, time}; -/// # use std::os::unix::io::AsRawFd; -/// # use tempfile::tempfile; -/// let f = tempfile().unwrap(); -/// let mut aiof = Box::pin(AioFsync::new(f.as_raw_fd(), AioFsyncMode::O_SYNC, -/// 0, SigevNone)); -/// aiof.as_mut().submit().expect("aio_fsync failed early"); -/// while (aiof.as_mut().error() == Err(Errno::EINPROGRESS)) { -/// thread::sleep(time::Duration::from_millis(10)); -/// } -/// aiof.as_mut().aio_return().expect("aio_fsync failed late"); -/// ``` -#[derive(Debug)] -#[repr(transparent)] -pub struct AioFsync { - aiocb: AioCb, - _pin: PhantomPinned, -} - -impl AioFsync { - unsafe_pinned!(aiocb: AioCb); - - /// Returns the operation's fsync mode: data and metadata or data only? - pub fn mode(&self) -> AioFsyncMode { - AioFsyncMode::try_from(self.aiocb.aiocb.0.aio_lio_opcode).unwrap() - } - - /// Create a new `AioFsync`. - /// - /// # Arguments - /// - /// * `fd`: File descriptor to sync. - /// * `mode`: Whether to sync file metadata too, or just data. - /// * `prio`: If POSIX Prioritized IO is supported, then the - /// operation will be prioritized at the process's - /// priority level minus `prio`. - /// * `sigev_notify`: Determines how you will be notified of event - /// completion. - pub fn new( - fd: RawFd, - mode: AioFsyncMode, - prio: i32, - sigev_notify: SigevNotify, - ) -> Self { - let mut aiocb = AioCb::common_init(fd, prio, sigev_notify); - // To save some memory, store mode in an unused field of the AioCb. - // True it isn't very much memory, but downstream creates will likely - // create an enum containing this and other AioCb variants and pack - // those enums into data structures like Vec, so it adds up. - aiocb.aiocb.0.aio_lio_opcode = mode as libc::c_int; - AioFsync { - aiocb, - _pin: PhantomPinned, - } - } -} - -impl Aio for AioFsync { - type Output = (); - - aio_methods!(); - - fn aio_return(self: Pin<&mut Self>) -> Result<()> { - self.aiocb().aio_return().map(drop) - } - - fn submit(mut self: Pin<&mut Self>) -> Result<()> { - let aiocb = &mut self.as_mut().aiocb().aiocb.0; - let mode = mem::replace(&mut aiocb.aio_lio_opcode, 0); - let p: *mut libc::aiocb = aiocb; - Errno::result(unsafe { libc::aio_fsync(mode, p) }).map(|_| { - self.aiocb().set_in_progress(); - }) - } -} - -// AioFsync does not need AsMut, since it can't be used with lio_listio - -impl AsRef<libc::aiocb> for AioFsync { - fn as_ref(&self) -> &libc::aiocb { - &self.aiocb.aiocb.0 - } -} - -/// Asynchronously reads from a file descriptor into a buffer -/// -/// # References -/// -/// [aio_read](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_read.html) -/// -/// # Examples -/// -/// -/// ``` -/// # use nix::errno::Errno; -/// # use nix::Error; -/// # use nix::sys::aio::*; -/// # use nix::sys::signal::SigevNotify; -/// # use std::{thread, time}; -/// # use std::io::Write; -/// # use std::os::unix::io::AsRawFd; -/// # use tempfile::tempfile; -/// const INITIAL: &[u8] = b"abcdef123456"; -/// const LEN: usize = 4; -/// let mut rbuf = vec![0; LEN]; -/// let mut f = tempfile().unwrap(); -/// f.write_all(INITIAL).unwrap(); -/// { -/// let mut aior = Box::pin( -/// AioRead::new( -/// f.as_raw_fd(), -/// 2, //offset -/// &mut rbuf, -/// 0, //priority -/// SigevNotify::SigevNone -/// ) -/// ); -/// aior.as_mut().submit().unwrap(); -/// while (aior.as_mut().error() == Err(Errno::EINPROGRESS)) { -/// thread::sleep(time::Duration::from_millis(10)); -/// } -/// assert_eq!(aior.as_mut().aio_return().unwrap(), LEN); -/// } -/// assert_eq!(rbuf, b"cdef"); -/// ``` -#[derive(Debug)] -#[repr(transparent)] -pub struct AioRead<'a> { - aiocb: AioCb, - _data: PhantomData<&'a [u8]>, - _pin: PhantomPinned, -} - -impl<'a> AioRead<'a> { - unsafe_pinned!(aiocb: AioCb); - - /// Returns the requested length of the aio operation in bytes - /// - /// This method returns the *requested* length of the operation. To get the - /// number of bytes actually read or written by a completed operation, use - /// `aio_return` instead. - pub fn nbytes(&self) -> usize { - self.aiocb.aiocb.0.aio_nbytes - } - - /// Create a new `AioRead`, placing the data in a mutable slice. - /// - /// # Arguments - /// - /// * `fd`: File descriptor to read from - /// * `offs`: File offset - /// * `buf`: A memory buffer. It must outlive the `AioRead`. - /// * `prio`: If POSIX Prioritized IO is supported, then the - /// operation will be prioritized at the process's - /// priority level minus `prio` - /// * `sigev_notify`: Determines how you will be notified of event - /// completion. - pub fn new( - fd: RawFd, - offs: off_t, - buf: &'a mut [u8], - prio: i32, - sigev_notify: SigevNotify, - ) -> Self { - let mut aiocb = AioCb::common_init(fd, prio, sigev_notify); - aiocb.aiocb.0.aio_nbytes = buf.len(); - aiocb.aiocb.0.aio_buf = buf.as_mut_ptr() as *mut c_void; - aiocb.aiocb.0.aio_lio_opcode = libc::LIO_READ; - aiocb.aiocb.0.aio_offset = offs; - AioRead { - aiocb, - _data: PhantomData, - _pin: PhantomPinned, - } - } - - /// Returns the file offset of the operation. - pub fn offset(&self) -> off_t { - self.aiocb.aiocb.0.aio_offset - } -} - -impl<'a> Aio for AioRead<'a> { - type Output = usize; - - aio_methods!(aio_read); -} - -impl<'a> AsMut<libc::aiocb> for AioRead<'a> { - fn as_mut(&mut self) -> &mut libc::aiocb { - &mut self.aiocb.aiocb.0 - } -} - -impl<'a> AsRef<libc::aiocb> for AioRead<'a> { - fn as_ref(&self) -> &libc::aiocb { - &self.aiocb.aiocb.0 - } -} - -/// Asynchronously reads from a file descriptor into a scatter/gather list of buffers. -/// -/// # References -/// -/// [aio_readv](https://www.freebsd.org/cgi/man.cgi?query=aio_readv) -/// -/// # Examples -/// -/// -#[cfg_attr(fbsd14, doc = " ```")] -#[cfg_attr(not(fbsd14), doc = " ```no_run")] -/// # use nix::errno::Errno; -/// # use nix::Error; -/// # use nix::sys::aio::*; -/// # use nix::sys::signal::SigevNotify; -/// # use std::{thread, time}; -/// # use std::io::{IoSliceMut, Write}; -/// # use std::os::unix::io::AsRawFd; -/// # use tempfile::tempfile; -/// const INITIAL: &[u8] = b"abcdef123456"; -/// let mut rbuf0 = vec![0; 4]; -/// let mut rbuf1 = vec![0; 2]; -/// let expected_len = rbuf0.len() + rbuf1.len(); -/// let mut rbufs = [IoSliceMut::new(&mut rbuf0), IoSliceMut::new(&mut rbuf1)]; -/// let mut f = tempfile().unwrap(); -/// f.write_all(INITIAL).unwrap(); -/// { -/// let mut aior = Box::pin( -/// AioReadv::new( -/// f.as_raw_fd(), -/// 2, //offset -/// &mut rbufs, -/// 0, //priority -/// SigevNotify::SigevNone -/// ) -/// ); -/// aior.as_mut().submit().unwrap(); -/// while (aior.as_mut().error() == Err(Errno::EINPROGRESS)) { -/// thread::sleep(time::Duration::from_millis(10)); -/// } -/// assert_eq!(aior.as_mut().aio_return().unwrap(), expected_len); -/// } -/// assert_eq!(rbuf0, b"cdef"); -/// assert_eq!(rbuf1, b"12"); -/// ``` -#[cfg(target_os = "freebsd")] -#[derive(Debug)] -#[repr(transparent)] -pub struct AioReadv<'a> { - aiocb: AioCb, - _data: PhantomData<&'a [&'a [u8]]>, - _pin: PhantomPinned, -} - -#[cfg(target_os = "freebsd")] -impl<'a> AioReadv<'a> { - unsafe_pinned!(aiocb: AioCb); - - /// Returns the number of buffers the operation will read into. - pub fn iovlen(&self) -> usize { - self.aiocb.aiocb.0.aio_nbytes - } - - /// Create a new `AioReadv`, placing the data in a list of mutable slices. - /// - /// # Arguments - /// - /// * `fd`: File descriptor to read from - /// * `offs`: File offset - /// * `bufs`: A scatter/gather list of memory buffers. They must - /// outlive the `AioReadv`. - /// * `prio`: If POSIX Prioritized IO is supported, then the - /// operation will be prioritized at the process's - /// priority level minus `prio` - /// * `sigev_notify`: Determines how you will be notified of event - /// completion. - pub fn new( - fd: RawFd, - offs: off_t, - bufs: &mut [IoSliceMut<'a>], - prio: i32, - sigev_notify: SigevNotify, - ) -> Self { - let mut aiocb = AioCb::common_init(fd, prio, sigev_notify); - // In vectored mode, aio_nbytes stores the length of the iovec array, - // not the byte count. - aiocb.aiocb.0.aio_nbytes = bufs.len(); - aiocb.aiocb.0.aio_buf = bufs.as_mut_ptr() as *mut c_void; - aiocb.aiocb.0.aio_lio_opcode = libc::LIO_READV; - aiocb.aiocb.0.aio_offset = offs; - AioReadv { - aiocb, - _data: PhantomData, - _pin: PhantomPinned, - } - } - - /// Returns the file offset of the operation. - pub fn offset(&self) -> off_t { - self.aiocb.aiocb.0.aio_offset - } -} - -#[cfg(target_os = "freebsd")] -impl<'a> Aio for AioReadv<'a> { - type Output = usize; - - aio_methods!(aio_readv); -} - -#[cfg(target_os = "freebsd")] -impl<'a> AsMut<libc::aiocb> for AioReadv<'a> { - fn as_mut(&mut self) -> &mut libc::aiocb { - &mut self.aiocb.aiocb.0 - } -} - -#[cfg(target_os = "freebsd")] -impl<'a> AsRef<libc::aiocb> for AioReadv<'a> { - fn as_ref(&self) -> &libc::aiocb { - &self.aiocb.aiocb.0 - } -} - -/// Asynchronously writes from a buffer to a file descriptor -/// -/// # References -/// -/// [aio_write](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_write.html) -/// -/// # Examples -/// -/// ``` -/// # use nix::errno::Errno; -/// # use nix::Error; -/// # use nix::sys::aio::*; -/// # use nix::sys::signal::SigevNotify; -/// # use std::{thread, time}; -/// # use std::os::unix::io::AsRawFd; -/// # use tempfile::tempfile; -/// const WBUF: &[u8] = b"abcdef123456"; -/// let mut f = tempfile().unwrap(); -/// let mut aiow = Box::pin( -/// AioWrite::new( -/// f.as_raw_fd(), -/// 2, //offset -/// WBUF, -/// 0, //priority -/// SigevNotify::SigevNone -/// ) -/// ); -/// aiow.as_mut().submit().unwrap(); -/// while (aiow.as_mut().error() == Err(Errno::EINPROGRESS)) { -/// thread::sleep(time::Duration::from_millis(10)); -/// } -/// assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len()); -/// ``` -#[derive(Debug)] -#[repr(transparent)] -pub struct AioWrite<'a> { - aiocb: AioCb, - _data: PhantomData<&'a [u8]>, - _pin: PhantomPinned, -} - -impl<'a> AioWrite<'a> { - unsafe_pinned!(aiocb: AioCb); - - /// Returns the requested length of the aio operation in bytes - /// - /// This method returns the *requested* length of the operation. To get the - /// number of bytes actually read or written by a completed operation, use - /// `aio_return` instead. - pub fn nbytes(&self) -> usize { - self.aiocb.aiocb.0.aio_nbytes - } - - /// Construct a new `AioWrite`. - /// - /// # Arguments - /// - /// * `fd`: File descriptor to write to - /// * `offs`: File offset - /// * `buf`: A memory buffer. It must outlive the `AioWrite`. - /// * `prio`: If POSIX Prioritized IO is supported, then the - /// operation will be prioritized at the process's - /// priority level minus `prio` - /// * `sigev_notify`: Determines how you will be notified of event - /// completion. - pub fn new( - fd: RawFd, - offs: off_t, - buf: &'a [u8], - prio: i32, - sigev_notify: SigevNotify, - ) -> Self { - let mut aiocb = AioCb::common_init(fd, prio, sigev_notify); - aiocb.aiocb.0.aio_nbytes = buf.len(); - // casting an immutable buffer to a mutable pointer looks unsafe, - // but technically its only unsafe to dereference it, not to create - // it. Type Safety guarantees that we'll never pass aiocb to - // aio_read or aio_readv. - aiocb.aiocb.0.aio_buf = buf.as_ptr() as *mut c_void; - aiocb.aiocb.0.aio_lio_opcode = libc::LIO_WRITE; - aiocb.aiocb.0.aio_offset = offs; - AioWrite { - aiocb, - _data: PhantomData, - _pin: PhantomPinned, - } - } - - /// Returns the file offset of the operation. - pub fn offset(&self) -> off_t { - self.aiocb.aiocb.0.aio_offset - } -} - -impl<'a> Aio for AioWrite<'a> { - type Output = usize; - - aio_methods!(aio_write); -} - -impl<'a> AsMut<libc::aiocb> for AioWrite<'a> { - fn as_mut(&mut self) -> &mut libc::aiocb { - &mut self.aiocb.aiocb.0 - } -} - -impl<'a> AsRef<libc::aiocb> for AioWrite<'a> { - fn as_ref(&self) -> &libc::aiocb { - &self.aiocb.aiocb.0 - } -} - -/// Asynchronously writes from a scatter/gather list of buffers to a file descriptor. -/// -/// # References -/// -/// [aio_writev](https://www.freebsd.org/cgi/man.cgi?query=aio_writev) -/// -/// # Examples -/// -#[cfg_attr(fbsd14, doc = " ```")] -#[cfg_attr(not(fbsd14), doc = " ```no_run")] -/// # use nix::errno::Errno; -/// # use nix::Error; -/// # use nix::sys::aio::*; -/// # use nix::sys::signal::SigevNotify; -/// # use std::{thread, time}; -/// # use std::io::IoSlice; -/// # use std::os::unix::io::AsRawFd; -/// # use tempfile::tempfile; -/// const wbuf0: &[u8] = b"abcdef"; -/// const wbuf1: &[u8] = b"123456"; -/// let len = wbuf0.len() + wbuf1.len(); -/// let wbufs = [IoSlice::new(wbuf0), IoSlice::new(wbuf1)]; -/// let mut f = tempfile().unwrap(); -/// let mut aiow = Box::pin( -/// AioWritev::new( -/// f.as_raw_fd(), -/// 2, //offset -/// &wbufs, -/// 0, //priority -/// SigevNotify::SigevNone -/// ) -/// ); -/// aiow.as_mut().submit().unwrap(); -/// while (aiow.as_mut().error() == Err(Errno::EINPROGRESS)) { -/// thread::sleep(time::Duration::from_millis(10)); -/// } -/// assert_eq!(aiow.as_mut().aio_return().unwrap(), len); -/// ``` -#[cfg(target_os = "freebsd")] -#[derive(Debug)] -#[repr(transparent)] -pub struct AioWritev<'a> { - aiocb: AioCb, - _data: PhantomData<&'a [&'a [u8]]>, - _pin: PhantomPinned, -} - -#[cfg(target_os = "freebsd")] -impl<'a> AioWritev<'a> { - unsafe_pinned!(aiocb: AioCb); - - /// Returns the number of buffers the operation will read into. - pub fn iovlen(&self) -> usize { - self.aiocb.aiocb.0.aio_nbytes - } - - /// Construct a new `AioWritev`. - /// - /// # Arguments - /// - /// * `fd`: File descriptor to write to - /// * `offs`: File offset - /// * `bufs`: A scatter/gather list of memory buffers. They must - /// outlive the `AioWritev`. - /// * `prio`: If POSIX Prioritized IO is supported, then the - /// operation will be prioritized at the process's - /// priority level minus `prio` - /// * `sigev_notify`: Determines how you will be notified of event - /// completion. - pub fn new( - fd: RawFd, - offs: off_t, - bufs: &[IoSlice<'a>], - prio: i32, - sigev_notify: SigevNotify, - ) -> Self { - let mut aiocb = AioCb::common_init(fd, prio, sigev_notify); - // In vectored mode, aio_nbytes stores the length of the iovec array, - // not the byte count. - aiocb.aiocb.0.aio_nbytes = bufs.len(); - // casting an immutable buffer to a mutable pointer looks unsafe, - // but technically its only unsafe to dereference it, not to create - // it. Type Safety guarantees that we'll never pass aiocb to - // aio_read or aio_readv. - aiocb.aiocb.0.aio_buf = bufs.as_ptr() as *mut c_void; - aiocb.aiocb.0.aio_lio_opcode = libc::LIO_WRITEV; - aiocb.aiocb.0.aio_offset = offs; - AioWritev { - aiocb, - _data: PhantomData, - _pin: PhantomPinned, - } - } - - /// Returns the file offset of the operation. - pub fn offset(&self) -> off_t { - self.aiocb.aiocb.0.aio_offset - } -} - -#[cfg(target_os = "freebsd")] -impl<'a> Aio for AioWritev<'a> { - type Output = usize; - - aio_methods!(aio_writev); -} - -#[cfg(target_os = "freebsd")] -impl<'a> AsMut<libc::aiocb> for AioWritev<'a> { - fn as_mut(&mut self) -> &mut libc::aiocb { - &mut self.aiocb.aiocb.0 - } -} - -#[cfg(target_os = "freebsd")] -impl<'a> AsRef<libc::aiocb> for AioWritev<'a> { - fn as_ref(&self) -> &libc::aiocb { - &self.aiocb.aiocb.0 - } -} - -/// Cancels outstanding AIO requests for a given file descriptor. -/// -/// # Examples -/// -/// Issue an aio operation, then cancel all outstanding operations on that file -/// descriptor. -/// -/// ``` -/// # use nix::errno::Errno; -/// # use nix::Error; -/// # use nix::sys::aio::*; -/// # use nix::sys::signal::SigevNotify; -/// # use std::{thread, time}; -/// # use std::io::Write; -/// # use std::os::unix::io::AsRawFd; -/// # use tempfile::tempfile; -/// let wbuf = b"CDEF"; -/// let mut f = tempfile().unwrap(); -/// let mut aiocb = Box::pin(AioWrite::new(f.as_raw_fd(), -/// 2, //offset -/// &wbuf[..], -/// 0, //priority -/// SigevNotify::SigevNone)); -/// aiocb.as_mut().submit().unwrap(); -/// let cs = aio_cancel_all(f.as_raw_fd()).unwrap(); -/// if cs == AioCancelStat::AioNotCanceled { -/// while (aiocb.as_mut().error() == Err(Errno::EINPROGRESS)) { -/// thread::sleep(time::Duration::from_millis(10)); -/// } -/// } -/// // Must call `aio_return`, but ignore the result -/// let _ = aiocb.as_mut().aio_return(); -/// ``` -/// -/// # References -/// -/// [`aio_cancel`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_cancel.html) -pub fn aio_cancel_all(fd: RawFd) -> Result<AioCancelStat> { - match unsafe { libc::aio_cancel(fd, ptr::null_mut()) } { - libc::AIO_CANCELED => Ok(AioCancelStat::AioCanceled), - libc::AIO_NOTCANCELED => Ok(AioCancelStat::AioNotCanceled), - libc::AIO_ALLDONE => Ok(AioCancelStat::AioAllDone), - -1 => Err(Errno::last()), - _ => panic!("unknown aio_cancel return value"), - } -} - -/// Suspends the calling process until at least one of the specified operations -/// have completed, a signal is delivered, or the timeout has passed. -/// -/// If `timeout` is `None`, `aio_suspend` will block indefinitely. -/// -/// # Examples -/// -/// Use `aio_suspend` to block until an aio operation completes. -/// -/// ``` -/// # use nix::sys::aio::*; -/// # use nix::sys::signal::SigevNotify; -/// # use std::os::unix::io::AsRawFd; -/// # use tempfile::tempfile; -/// const WBUF: &[u8] = b"abcdef123456"; -/// let mut f = tempfile().unwrap(); -/// let mut aiocb = Box::pin(AioWrite::new(f.as_raw_fd(), -/// 2, //offset -/// WBUF, -/// 0, //priority -/// SigevNotify::SigevNone)); -/// aiocb.as_mut().submit().unwrap(); -/// aio_suspend(&[&*aiocb], None).expect("aio_suspend failed"); -/// assert_eq!(aiocb.as_mut().aio_return().unwrap() as usize, WBUF.len()); -/// ``` -/// # References -/// -/// [`aio_suspend`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_suspend.html) -pub fn aio_suspend( - list: &[&dyn AsRef<libc::aiocb>], - timeout: Option<TimeSpec>, -) -> Result<()> { - let p = list as *const [&dyn AsRef<libc::aiocb>] - as *const [*const libc::aiocb] as *const *const libc::aiocb; - let timep = match timeout { - None => ptr::null::<libc::timespec>(), - Some(x) => x.as_ref() as *const libc::timespec, - }; - Errno::result(unsafe { libc::aio_suspend(p, list.len() as i32, timep) }) - .map(drop) -} - -/// Submits multiple asynchronous I/O requests with a single system call. -/// -/// They are not guaranteed to complete atomically, and the order in which the -/// requests are carried out is not specified. Reads, and writes may be freely -/// mixed. -/// -/// # Examples -/// -/// Use `lio_listio` to submit an aio operation and wait for its completion. In -/// this case, there is no need to use aio_suspend to wait or `error` to poll. -/// This mode is useful for otherwise-synchronous programs that want to execute -/// a handful of I/O operations in parallel. -/// ``` -/// # use std::os::unix::io::AsRawFd; -/// # use nix::sys::aio::*; -/// # use nix::sys::signal::SigevNotify; -/// # use tempfile::tempfile; -/// const WBUF: &[u8] = b"abcdef123456"; -/// let mut f = tempfile().unwrap(); -/// let mut aiow = Box::pin(AioWrite::new( -/// f.as_raw_fd(), -/// 2, // offset -/// WBUF, -/// 0, // priority -/// SigevNotify::SigevNone -/// )); -/// lio_listio(LioMode::LIO_WAIT, &mut[aiow.as_mut()], SigevNotify::SigevNone) -/// .unwrap(); -/// // At this point, we are guaranteed that aiow is complete. -/// assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len()); -/// ``` -/// -/// Use `lio_listio` to submit multiple asynchronous operations with a single -/// syscall, but receive notification individually. This is an efficient -/// technique for reducing overall context-switch overhead, especially when -/// combined with kqueue. -/// ``` -/// # use std::os::unix::io::AsRawFd; -/// # use std::thread; -/// # use std::time; -/// # use nix::errno::Errno; -/// # use nix::sys::aio::*; -/// # use nix::sys::signal::SigevNotify; -/// # use tempfile::tempfile; -/// const WBUF: &[u8] = b"abcdef123456"; -/// let mut f = tempfile().unwrap(); -/// let mut aiow = Box::pin(AioWrite::new( -/// f.as_raw_fd(), -/// 2, // offset -/// WBUF, -/// 0, // priority -/// SigevNotify::SigevNone -/// )); -/// lio_listio(LioMode::LIO_NOWAIT, &mut[aiow.as_mut()], SigevNotify::SigevNone) -/// .unwrap(); -/// // We must wait for the completion of each individual operation -/// while (aiow.as_mut().error() == Err(Errno::EINPROGRESS)) { -/// thread::sleep(time::Duration::from_millis(10)); -/// } -/// assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len()); -/// ``` -/// -/// Use `lio_listio` to submit multiple operations, and receive notification -/// only when all of them are complete. This can be useful when there is some -/// logical relationship between the operations. But beware! Errors or system -/// resource limitations may cause `lio_listio` to return `EIO`, `EAGAIN`, or -/// `EINTR`, in which case some but not all operations may have been submitted. -/// In that case, you must check the status of each individual operation, and -/// possibly resubmit some. -/// ``` -/// # use libc::c_int; -/// # use std::os::unix::io::AsRawFd; -/// # use std::sync::atomic::{AtomicBool, Ordering}; -/// # use std::thread; -/// # use std::time; -/// # use lazy_static::lazy_static; -/// # use nix::errno::Errno; -/// # use nix::sys::aio::*; -/// # use nix::sys::signal::*; -/// # use tempfile::tempfile; -/// lazy_static! { -/// pub static ref SIGNALED: AtomicBool = AtomicBool::new(false); -/// } -/// -/// extern fn sigfunc(_: c_int) { -/// SIGNALED.store(true, Ordering::Relaxed); -/// } -/// let sa = SigAction::new(SigHandler::Handler(sigfunc), -/// SaFlags::SA_RESETHAND, -/// SigSet::empty()); -/// SIGNALED.store(false, Ordering::Relaxed); -/// unsafe { sigaction(Signal::SIGUSR2, &sa) }.unwrap(); -/// -/// const WBUF: &[u8] = b"abcdef123456"; -/// let mut f = tempfile().unwrap(); -/// let mut aiow = Box::pin(AioWrite::new( -/// f.as_raw_fd(), -/// 2, // offset -/// WBUF, -/// 0, // priority -/// SigevNotify::SigevNone -/// )); -/// let sev = SigevNotify::SigevSignal { signal: Signal::SIGUSR2, si_value: 0 }; -/// lio_listio(LioMode::LIO_NOWAIT, &mut[aiow.as_mut()], sev).unwrap(); -/// while !SIGNALED.load(Ordering::Relaxed) { -/// thread::sleep(time::Duration::from_millis(10)); -/// } -/// // At this point, since `lio_listio` returned success and delivered its -/// // notification, we know that all operations are complete. -/// assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len()); -/// ``` -pub fn lio_listio( - mode: LioMode, - list: &mut [Pin<&mut dyn AsMut<libc::aiocb>>], - sigev_notify: SigevNotify, -) -> Result<()> { - let p = list as *mut [Pin<&mut dyn AsMut<libc::aiocb>>] - as *mut [*mut libc::aiocb] as *mut *mut libc::aiocb; - let sigev = SigEvent::new(sigev_notify); - let sigevp = &mut sigev.sigevent() as *mut libc::sigevent; - Errno::result(unsafe { - libc::lio_listio(mode as i32, p, list.len() as i32, sigevp) - }) - .map(drop) -} - -#[cfg(test)] -mod t { - use super::*; - - /// aio_suspend relies on casting Rust Aio* struct pointers to libc::aiocb - /// pointers. This test ensures that such casts are valid. - #[test] - fn casting() { - let sev = SigevNotify::SigevNone; - let aiof = AioFsync::new(666, AioFsyncMode::O_SYNC, 0, sev); - assert_eq!( - aiof.as_ref() as *const libc::aiocb, - &aiof as *const AioFsync as *const libc::aiocb - ); - - let mut rbuf = []; - let aior = AioRead::new(666, 0, &mut rbuf, 0, sev); - assert_eq!( - aior.as_ref() as *const libc::aiocb, - &aior as *const AioRead as *const libc::aiocb - ); - - let wbuf = []; - let aiow = AioWrite::new(666, 0, &wbuf, 0, sev); - assert_eq!( - aiow.as_ref() as *const libc::aiocb, - &aiow as *const AioWrite as *const libc::aiocb - ); - } - - #[cfg(target_os = "freebsd")] - #[test] - fn casting_vectored() { - let sev = SigevNotify::SigevNone; - - let mut rbuf = []; - let mut rbufs = [IoSliceMut::new(&mut rbuf)]; - let aiorv = AioReadv::new(666, 0, &mut rbufs[..], 0, sev); - assert_eq!( - aiorv.as_ref() as *const libc::aiocb, - &aiorv as *const AioReadv as *const libc::aiocb - ); - - let wbuf = []; - let wbufs = [IoSlice::new(&wbuf)]; - let aiowv = AioWritev::new(666, 0, &wbufs, 0, sev); - assert_eq!( - aiowv.as_ref() as *const libc::aiocb, - &aiowv as *const AioWritev as *const libc::aiocb - ); - } -} diff --git a/vendor/nix/src/sys/epoll.rs b/vendor/nix/src/sys/epoll.rs deleted file mode 100644 index 58def2e78..000000000 --- a/vendor/nix/src/sys/epoll.rs +++ /dev/null @@ -1,128 +0,0 @@ -use crate::errno::Errno; -use crate::Result; -use libc::{self, c_int}; -use std::mem; -use std::os::unix::io::RawFd; -use std::ptr; - -libc_bitflags!( - pub struct EpollFlags: c_int { - EPOLLIN; - EPOLLPRI; - EPOLLOUT; - EPOLLRDNORM; - EPOLLRDBAND; - EPOLLWRNORM; - EPOLLWRBAND; - EPOLLMSG; - EPOLLERR; - EPOLLHUP; - EPOLLRDHUP; - EPOLLEXCLUSIVE; - #[cfg(not(target_arch = "mips"))] - EPOLLWAKEUP; - EPOLLONESHOT; - EPOLLET; - } -); - -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -#[repr(i32)] -#[non_exhaustive] -pub enum EpollOp { - EpollCtlAdd = libc::EPOLL_CTL_ADD, - EpollCtlDel = libc::EPOLL_CTL_DEL, - EpollCtlMod = libc::EPOLL_CTL_MOD, -} - -libc_bitflags! { - pub struct EpollCreateFlags: c_int { - EPOLL_CLOEXEC; - } -} - -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -#[repr(transparent)] -pub struct EpollEvent { - event: libc::epoll_event, -} - -impl EpollEvent { - pub fn new(events: EpollFlags, data: u64) -> Self { - EpollEvent { - event: libc::epoll_event { - events: events.bits() as u32, - u64: data, - }, - } - } - - pub fn empty() -> Self { - unsafe { mem::zeroed::<EpollEvent>() } - } - - pub fn events(&self) -> EpollFlags { - EpollFlags::from_bits(self.event.events as c_int).unwrap() - } - - pub fn data(&self) -> u64 { - self.event.u64 - } -} - -#[inline] -pub fn epoll_create() -> Result<RawFd> { - let res = unsafe { libc::epoll_create(1024) }; - - Errno::result(res) -} - -#[inline] -pub fn epoll_create1(flags: EpollCreateFlags) -> Result<RawFd> { - let res = unsafe { libc::epoll_create1(flags.bits()) }; - - Errno::result(res) -} - -#[inline] -pub fn epoll_ctl<'a, T>( - epfd: RawFd, - op: EpollOp, - fd: RawFd, - event: T, -) -> Result<()> -where - T: Into<Option<&'a mut EpollEvent>>, -{ - let mut event: Option<&mut EpollEvent> = event.into(); - if event.is_none() && op != EpollOp::EpollCtlDel { - Err(Errno::EINVAL) - } else { - let res = unsafe { - if let Some(ref mut event) = event { - libc::epoll_ctl(epfd, op as c_int, fd, &mut event.event) - } else { - libc::epoll_ctl(epfd, op as c_int, fd, ptr::null_mut()) - } - }; - Errno::result(res).map(drop) - } -} - -#[inline] -pub fn epoll_wait( - epfd: RawFd, - events: &mut [EpollEvent], - timeout_ms: isize, -) -> Result<usize> { - let res = unsafe { - libc::epoll_wait( - epfd, - events.as_mut_ptr() as *mut libc::epoll_event, - events.len() as c_int, - timeout_ms as c_int, - ) - }; - - Errno::result(res).map(|r| r as usize) -} diff --git a/vendor/nix/src/sys/event.rs b/vendor/nix/src/sys/event.rs deleted file mode 100644 index d8ad628ea..000000000 --- a/vendor/nix/src/sys/event.rs +++ /dev/null @@ -1,374 +0,0 @@ -/* TOOD: Implement for other kqueue based systems - */ - -use crate::{Errno, Result}; -#[cfg(not(target_os = "netbsd"))] -use libc::{c_int, c_long, intptr_t, time_t, timespec, uintptr_t}; -#[cfg(target_os = "netbsd")] -use libc::{c_long, intptr_t, size_t, time_t, timespec, uintptr_t}; -use std::convert::TryInto; -use std::mem; -use std::os::unix::io::RawFd; -use std::ptr; - -// Redefine kevent in terms of programmer-friendly enums and bitfields. -#[repr(C)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct KEvent { - kevent: libc::kevent, -} - -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "openbsd" -))] -type type_of_udata = *mut libc::c_void; -#[cfg(any(target_os = "netbsd"))] -type type_of_udata = intptr_t; - -#[cfg(target_os = "netbsd")] -type type_of_event_filter = u32; -#[cfg(not(target_os = "netbsd"))] -type type_of_event_filter = i16; -libc_enum! { - #[cfg_attr(target_os = "netbsd", repr(u32))] - #[cfg_attr(not(target_os = "netbsd"), repr(i16))] - #[non_exhaustive] - pub enum EventFilter { - EVFILT_AIO, - /// Returns whenever there is no remaining data in the write buffer - #[cfg(target_os = "freebsd")] - EVFILT_EMPTY, - #[cfg(target_os = "dragonfly")] - EVFILT_EXCEPT, - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos"))] - EVFILT_FS, - #[cfg(target_os = "freebsd")] - EVFILT_LIO, - #[cfg(any(target_os = "ios", target_os = "macos"))] - EVFILT_MACHPORT, - EVFILT_PROC, - /// Returns events associated with the process referenced by a given - /// process descriptor, created by `pdfork()`. The events to monitor are: - /// - /// - NOTE_EXIT: the process has exited. The exit status will be stored in data. - #[cfg(target_os = "freebsd")] - EVFILT_PROCDESC, - EVFILT_READ, - /// Returns whenever an asynchronous `sendfile()` call completes. - #[cfg(target_os = "freebsd")] - EVFILT_SENDFILE, - EVFILT_SIGNAL, - EVFILT_TIMER, - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos"))] - EVFILT_USER, - #[cfg(any(target_os = "ios", target_os = "macos"))] - EVFILT_VM, - EVFILT_VNODE, - EVFILT_WRITE, - } - impl TryFrom<type_of_event_filter> -} - -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "openbsd" -))] -pub type type_of_event_flag = u16; -#[cfg(any(target_os = "netbsd"))] -pub type type_of_event_flag = u32; -libc_bitflags! { - pub struct EventFlag: type_of_event_flag { - EV_ADD; - EV_CLEAR; - EV_DELETE; - EV_DISABLE; - #[cfg(any(target_os = "dragonfly", target_os = "freebsd", - target_os = "ios", target_os = "macos", - target_os = "netbsd", target_os = "openbsd"))] - EV_DISPATCH; - #[cfg(target_os = "freebsd")] - EV_DROP; - EV_ENABLE; - EV_EOF; - EV_ERROR; - #[cfg(any(target_os = "macos", target_os = "ios"))] - EV_FLAG0; - EV_FLAG1; - #[cfg(target_os = "dragonfly")] - EV_NODATA; - EV_ONESHOT; - #[cfg(any(target_os = "macos", target_os = "ios"))] - EV_OOBAND; - #[cfg(any(target_os = "macos", target_os = "ios"))] - EV_POLL; - #[cfg(any(target_os = "dragonfly", target_os = "freebsd", - target_os = "ios", target_os = "macos", - target_os = "netbsd", target_os = "openbsd"))] - EV_RECEIPT; - } -} - -libc_bitflags!( - pub struct FilterFlag: u32 { - #[cfg(any(target_os = "macos", target_os = "ios"))] - NOTE_ABSOLUTE; - NOTE_ATTRIB; - NOTE_CHILD; - NOTE_DELETE; - #[cfg(target_os = "openbsd")] - NOTE_EOF; - NOTE_EXEC; - NOTE_EXIT; - #[cfg(any(target_os = "macos", target_os = "ios"))] - NOTE_EXITSTATUS; - NOTE_EXTEND; - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] - NOTE_FFAND; - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] - NOTE_FFCOPY; - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] - NOTE_FFCTRLMASK; - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] - NOTE_FFLAGSMASK; - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] - NOTE_FFNOP; - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] - NOTE_FFOR; - NOTE_FORK; - NOTE_LINK; - NOTE_LOWAT; - #[cfg(target_os = "freebsd")] - NOTE_MSECONDS; - #[cfg(any(target_os = "macos", target_os = "ios"))] - NOTE_NONE; - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))] - NOTE_NSECONDS; - #[cfg(target_os = "dragonfly")] - NOTE_OOB; - NOTE_PCTRLMASK; - NOTE_PDATAMASK; - NOTE_RENAME; - NOTE_REVOKE; - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))] - NOTE_SECONDS; - #[cfg(any(target_os = "macos", target_os = "ios"))] - NOTE_SIGNAL; - NOTE_TRACK; - NOTE_TRACKERR; - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] - NOTE_TRIGGER; - #[cfg(target_os = "openbsd")] - NOTE_TRUNCATE; - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))] - NOTE_USECONDS; - #[cfg(any(target_os = "macos", target_os = "ios"))] - NOTE_VM_ERROR; - #[cfg(any(target_os = "macos", target_os = "ios"))] - NOTE_VM_PRESSURE; - #[cfg(any(target_os = "macos", target_os = "ios"))] - NOTE_VM_PRESSURE_SUDDEN_TERMINATE; - #[cfg(any(target_os = "macos", target_os = "ios"))] - NOTE_VM_PRESSURE_TERMINATE; - NOTE_WRITE; - } -); - -pub fn kqueue() -> Result<RawFd> { - let res = unsafe { libc::kqueue() }; - - Errno::result(res) -} - -// KEvent can't derive Send because on some operating systems, udata is defined -// as a void*. However, KEvent's public API always treats udata as an intptr_t, -// which is safe to Send. -unsafe impl Send for KEvent {} - -impl KEvent { - #[allow(clippy::needless_update)] // Not needless on all platforms. - pub fn new( - ident: uintptr_t, - filter: EventFilter, - flags: EventFlag, - fflags: FilterFlag, - data: intptr_t, - udata: intptr_t, - ) -> KEvent { - KEvent { - kevent: libc::kevent { - ident, - filter: filter as type_of_event_filter, - flags: flags.bits(), - fflags: fflags.bits(), - // data can be either i64 or intptr_t, depending on platform - data: data as _, - udata: udata as type_of_udata, - ..unsafe { mem::zeroed() } - }, - } - } - - pub fn ident(&self) -> uintptr_t { - self.kevent.ident - } - - pub fn filter(&self) -> Result<EventFilter> { - self.kevent.filter.try_into() - } - - pub fn flags(&self) -> EventFlag { - EventFlag::from_bits(self.kevent.flags).unwrap() - } - - pub fn fflags(&self) -> FilterFlag { - FilterFlag::from_bits(self.kevent.fflags).unwrap() - } - - pub fn data(&self) -> intptr_t { - self.kevent.data as intptr_t - } - - pub fn udata(&self) -> intptr_t { - self.kevent.udata as intptr_t - } -} - -pub fn kevent( - kq: RawFd, - changelist: &[KEvent], - eventlist: &mut [KEvent], - timeout_ms: usize, -) -> Result<usize> { - // Convert ms to timespec - let timeout = timespec { - tv_sec: (timeout_ms / 1000) as time_t, - tv_nsec: ((timeout_ms % 1000) * 1_000_000) as c_long, - }; - - kevent_ts(kq, changelist, eventlist, Some(timeout)) -} - -#[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "openbsd" -))] -type type_of_nchanges = c_int; -#[cfg(target_os = "netbsd")] -type type_of_nchanges = size_t; - -pub fn kevent_ts( - kq: RawFd, - changelist: &[KEvent], - eventlist: &mut [KEvent], - timeout_opt: Option<timespec>, -) -> Result<usize> { - let res = unsafe { - libc::kevent( - kq, - changelist.as_ptr() as *const libc::kevent, - changelist.len() as type_of_nchanges, - eventlist.as_mut_ptr() as *mut libc::kevent, - eventlist.len() as type_of_nchanges, - if let Some(ref timeout) = timeout_opt { - timeout as *const timespec - } else { - ptr::null() - }, - ) - }; - - Errno::result(res).map(|r| r as usize) -} - -#[inline] -pub fn ev_set( - ev: &mut KEvent, - ident: usize, - filter: EventFilter, - flags: EventFlag, - fflags: FilterFlag, - udata: intptr_t, -) { - ev.kevent.ident = ident as uintptr_t; - ev.kevent.filter = filter as type_of_event_filter; - ev.kevent.flags = flags.bits(); - ev.kevent.fflags = fflags.bits(); - ev.kevent.data = 0; - ev.kevent.udata = udata as type_of_udata; -} - -#[test] -fn test_struct_kevent() { - use std::mem; - - let udata: intptr_t = 12345; - - let actual = KEvent::new( - 0xdead_beef, - EventFilter::EVFILT_READ, - EventFlag::EV_ONESHOT | EventFlag::EV_ADD, - FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT, - 0x1337, - udata, - ); - assert_eq!(0xdead_beef, actual.ident()); - let filter = actual.kevent.filter; - assert_eq!(libc::EVFILT_READ, filter); - assert_eq!(libc::EV_ONESHOT | libc::EV_ADD, actual.flags().bits()); - assert_eq!(libc::NOTE_CHILD | libc::NOTE_EXIT, actual.fflags().bits()); - assert_eq!(0x1337, actual.data()); - assert_eq!(udata as type_of_udata, actual.udata() as type_of_udata); - assert_eq!(mem::size_of::<libc::kevent>(), mem::size_of::<KEvent>()); -} - -#[test] -fn test_kevent_filter() { - let udata: intptr_t = 12345; - - let actual = KEvent::new( - 0xdead_beef, - EventFilter::EVFILT_READ, - EventFlag::EV_ONESHOT | EventFlag::EV_ADD, - FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT, - 0x1337, - udata, - ); - assert_eq!(EventFilter::EVFILT_READ, actual.filter().unwrap()); -} diff --git a/vendor/nix/src/sys/eventfd.rs b/vendor/nix/src/sys/eventfd.rs deleted file mode 100644 index cd906720c..000000000 --- a/vendor/nix/src/sys/eventfd.rs +++ /dev/null @@ -1,17 +0,0 @@ -use crate::errno::Errno; -use crate::Result; -use std::os::unix::io::RawFd; - -libc_bitflags! { - pub struct EfdFlags: libc::c_int { - EFD_CLOEXEC; // Since Linux 2.6.27 - EFD_NONBLOCK; // Since Linux 2.6.27 - EFD_SEMAPHORE; // Since Linux 2.6.30 - } -} - -pub fn eventfd(initval: libc::c_uint, flags: EfdFlags) -> Result<RawFd> { - let res = unsafe { libc::eventfd(initval, flags.bits()) }; - - Errno::result(res).map(|r| r as RawFd) -} diff --git a/vendor/nix/src/sys/inotify.rs b/vendor/nix/src/sys/inotify.rs deleted file mode 100644 index 84356ec70..000000000 --- a/vendor/nix/src/sys/inotify.rs +++ /dev/null @@ -1,248 +0,0 @@ -//! Monitoring API for filesystem events. -//! -//! Inotify is a Linux-only API to monitor filesystems events. -//! -//! For more documentation, please read [inotify(7)](https://man7.org/linux/man-pages/man7/inotify.7.html). -//! -//! # Examples -//! -//! Monitor all events happening in directory "test": -//! ```no_run -//! # use nix::sys::inotify::{AddWatchFlags,InitFlags,Inotify}; -//! # -//! // We create a new inotify instance. -//! let instance = Inotify::init(InitFlags::empty()).unwrap(); -//! -//! // We add a new watch on directory "test" for all events. -//! let wd = instance.add_watch("test", AddWatchFlags::IN_ALL_EVENTS).unwrap(); -//! -//! loop { -//! // We read from our inotify instance for events. -//! let events = instance.read_events().unwrap(); -//! println!("Events: {:?}", events); -//! } -//! ``` - -use crate::errno::Errno; -use crate::unistd::read; -use crate::NixPath; -use crate::Result; -use cfg_if::cfg_if; -use libc::{c_char, c_int}; -use std::ffi::{CStr, OsStr, OsString}; -use std::mem::{size_of, MaybeUninit}; -use std::os::unix::ffi::OsStrExt; -use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; -use std::ptr; - -libc_bitflags! { - /// Configuration options for [`inotify_add_watch`](fn.inotify_add_watch.html). - pub struct AddWatchFlags: u32 { - /// File was accessed. - IN_ACCESS; - /// File was modified. - IN_MODIFY; - /// Metadata changed. - IN_ATTRIB; - /// Writable file was closed. - IN_CLOSE_WRITE; - /// Nonwritable file was closed. - IN_CLOSE_NOWRITE; - /// File was opened. - IN_OPEN; - /// File was moved from X. - IN_MOVED_FROM; - /// File was moved to Y. - IN_MOVED_TO; - /// Subfile was created. - IN_CREATE; - /// Subfile was deleted. - IN_DELETE; - /// Self was deleted. - IN_DELETE_SELF; - /// Self was moved. - IN_MOVE_SELF; - - /// Backing filesystem was unmounted. - IN_UNMOUNT; - /// Event queue overflowed. - IN_Q_OVERFLOW; - /// File was ignored. - IN_IGNORED; - - /// Combination of `IN_CLOSE_WRITE` and `IN_CLOSE_NOWRITE`. - IN_CLOSE; - /// Combination of `IN_MOVED_FROM` and `IN_MOVED_TO`. - IN_MOVE; - - /// Only watch the path if it is a directory. - IN_ONLYDIR; - /// Don't follow symlinks. - IN_DONT_FOLLOW; - - /// Event occurred against directory. - IN_ISDIR; - /// Only send event once. - IN_ONESHOT; - /// All of the events. - IN_ALL_EVENTS; - } -} - -libc_bitflags! { - /// Configuration options for [`inotify_init1`](fn.inotify_init1.html). - pub struct InitFlags: c_int { - /// Set the `FD_CLOEXEC` flag on the file descriptor. - IN_CLOEXEC; - /// Set the `O_NONBLOCK` flag on the open file description referred to by the new file descriptor. - IN_NONBLOCK; - } -} - -/// An inotify instance. This is also a file descriptor, you can feed it to -/// other interfaces consuming file descriptors, epoll for example. -#[derive(Debug, Clone, Copy)] -pub struct Inotify { - fd: RawFd, -} - -/// This object is returned when you create a new watch on an inotify instance. -/// It is then returned as part of an event once triggered. It allows you to -/// know which watch triggered which event. -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Ord, PartialOrd)] -pub struct WatchDescriptor { - wd: i32, -} - -/// A single inotify event. -/// -/// For more documentation see, [inotify(7)](https://man7.org/linux/man-pages/man7/inotify.7.html). -#[derive(Debug)] -pub struct InotifyEvent { - /// Watch descriptor. This field corresponds to the watch descriptor you - /// were issued when calling add_watch. It allows you to know which watch - /// this event comes from. - pub wd: WatchDescriptor, - /// Event mask. This field is a bitfield describing the exact event that - /// occured. - pub mask: AddWatchFlags, - /// This cookie is a number that allows you to connect related events. For - /// now only IN_MOVED_FROM and IN_MOVED_TO can be connected. - pub cookie: u32, - /// Filename. This field exists only if the event was triggered for a file - /// inside the watched directory. - pub name: Option<OsString>, -} - -impl Inotify { - /// Initialize a new inotify instance. - /// - /// Returns a Result containing an inotify instance. - /// - /// For more information see, [inotify_init(2)](https://man7.org/linux/man-pages/man2/inotify_init.2.html). - pub fn init(flags: InitFlags) -> Result<Inotify> { - let res = Errno::result(unsafe { libc::inotify_init1(flags.bits()) }); - - res.map(|fd| Inotify { fd }) - } - - /// Adds a new watch on the target file or directory. - /// - /// Returns a watch descriptor. This is not a File Descriptor! - /// - /// For more information see, [inotify_add_watch(2)](https://man7.org/linux/man-pages/man2/inotify_add_watch.2.html). - pub fn add_watch<P: ?Sized + NixPath>( - self, - path: &P, - mask: AddWatchFlags, - ) -> Result<WatchDescriptor> { - let res = path.with_nix_path(|cstr| unsafe { - libc::inotify_add_watch(self.fd, cstr.as_ptr(), mask.bits()) - })?; - - Errno::result(res).map(|wd| WatchDescriptor { wd }) - } - - /// Removes an existing watch using the watch descriptor returned by - /// inotify_add_watch. - /// - /// Returns an EINVAL error if the watch descriptor is invalid. - /// - /// For more information see, [inotify_rm_watch(2)](https://man7.org/linux/man-pages/man2/inotify_rm_watch.2.html). - pub fn rm_watch(self, wd: WatchDescriptor) -> Result<()> { - cfg_if! { - if #[cfg(target_os = "linux")] { - let arg = wd.wd; - } else if #[cfg(target_os = "android")] { - let arg = wd.wd as u32; - } - } - let res = unsafe { libc::inotify_rm_watch(self.fd, arg) }; - - Errno::result(res).map(drop) - } - - /// Reads a collection of events from the inotify file descriptor. This call - /// can either be blocking or non blocking depending on whether IN_NONBLOCK - /// was set at initialization. - /// - /// Returns as many events as available. If the call was non blocking and no - /// events could be read then the EAGAIN error is returned. - pub fn read_events(self) -> Result<Vec<InotifyEvent>> { - let header_size = size_of::<libc::inotify_event>(); - const BUFSIZ: usize = 4096; - let mut buffer = [0u8; BUFSIZ]; - let mut events = Vec::new(); - let mut offset = 0; - - let nread = read(self.fd, &mut buffer)?; - - while (nread - offset) >= header_size { - let event = unsafe { - let mut event = MaybeUninit::<libc::inotify_event>::uninit(); - ptr::copy_nonoverlapping( - buffer.as_ptr().add(offset), - event.as_mut_ptr() as *mut u8, - (BUFSIZ - offset).min(header_size), - ); - event.assume_init() - }; - - let name = match event.len { - 0 => None, - _ => { - let ptr = unsafe { - buffer.as_ptr().add(offset + header_size) - as *const c_char - }; - let cstr = unsafe { CStr::from_ptr(ptr) }; - - Some(OsStr::from_bytes(cstr.to_bytes()).to_owned()) - } - }; - - events.push(InotifyEvent { - wd: WatchDescriptor { wd: event.wd }, - mask: AddWatchFlags::from_bits_truncate(event.mask), - cookie: event.cookie, - name, - }); - - offset += header_size + event.len as usize; - } - - Ok(events) - } -} - -impl AsRawFd for Inotify { - fn as_raw_fd(&self) -> RawFd { - self.fd - } -} - -impl FromRawFd for Inotify { - unsafe fn from_raw_fd(fd: RawFd) -> Self { - Inotify { fd } - } -} diff --git a/vendor/nix/src/sys/ioctl/bsd.rs b/vendor/nix/src/sys/ioctl/bsd.rs deleted file mode 100644 index 307994cb9..000000000 --- a/vendor/nix/src/sys/ioctl/bsd.rs +++ /dev/null @@ -1,129 +0,0 @@ -/// The datatype used for the ioctl number -#[doc(hidden)] -#[cfg(not(target_os = "illumos"))] -pub type ioctl_num_type = ::libc::c_ulong; - -#[doc(hidden)] -#[cfg(target_os = "illumos")] -pub type ioctl_num_type = ::libc::c_int; - -/// The datatype used for the 3rd argument -#[doc(hidden)] -pub type ioctl_param_type = ::libc::c_int; - -mod consts { - use crate::sys::ioctl::ioctl_num_type; - #[doc(hidden)] - pub const VOID: ioctl_num_type = 0x2000_0000; - #[doc(hidden)] - pub const OUT: ioctl_num_type = 0x4000_0000; - #[doc(hidden)] - #[allow(overflowing_literals)] - pub const IN: ioctl_num_type = 0x8000_0000; - #[doc(hidden)] - pub const INOUT: ioctl_num_type = IN | OUT; - #[doc(hidden)] - pub const IOCPARM_MASK: ioctl_num_type = 0x1fff; -} - -pub use self::consts::*; - -#[macro_export] -#[doc(hidden)] -macro_rules! ioc { - ($inout:expr, $group:expr, $num:expr, $len:expr) => { - $inout - | (($len as $crate::sys::ioctl::ioctl_num_type - & $crate::sys::ioctl::IOCPARM_MASK) - << 16) - | (($group as $crate::sys::ioctl::ioctl_num_type) << 8) - | ($num as $crate::sys::ioctl::ioctl_num_type) - }; -} - -/// Generate an ioctl request code for a command that passes no data. -/// -/// This is equivalent to the `_IO()` macro exposed by the C ioctl API. -/// -/// You should only use this macro directly if the `ioctl` you're working -/// with is "bad" and you cannot use `ioctl_none!()` directly. -/// -/// # Example -/// -/// ``` -/// # #[macro_use] extern crate nix; -/// const KVMIO: u8 = 0xAE; -/// ioctl_write_int_bad!(kvm_create_vm, request_code_none!(KVMIO, 0x03)); -/// # fn main() {} -/// ``` -#[macro_export(local_inner_macros)] -macro_rules! request_code_none { - ($g:expr, $n:expr) => { - ioc!($crate::sys::ioctl::VOID, $g, $n, 0) - }; -} - -/// Generate an ioctl request code for a command that passes an integer -/// -/// This is equivalent to the `_IOWINT()` macro exposed by the C ioctl API. -/// -/// You should only use this macro directly if the `ioctl` you're working -/// with is "bad" and you cannot use `ioctl_write_int!()` directly. -#[macro_export(local_inner_macros)] -macro_rules! request_code_write_int { - ($g:expr, $n:expr) => { - ioc!( - $crate::sys::ioctl::VOID, - $g, - $n, - ::std::mem::size_of::<$crate::libc::c_int>() - ) - }; -} - -/// Generate an ioctl request code for a command that reads. -/// -/// This is equivalent to the `_IOR()` macro exposed by the C ioctl API. -/// -/// You should only use this macro directly if the `ioctl` you're working -/// with is "bad" and you cannot use `ioctl_read!()` directly. -/// -/// The read/write direction is relative to userland, so this -/// command would be userland is reading and the kernel is -/// writing. -#[macro_export(local_inner_macros)] -macro_rules! request_code_read { - ($g:expr, $n:expr, $len:expr) => { - ioc!($crate::sys::ioctl::OUT, $g, $n, $len) - }; -} - -/// Generate an ioctl request code for a command that writes. -/// -/// This is equivalent to the `_IOW()` macro exposed by the C ioctl API. -/// -/// You should only use this macro directly if the `ioctl` you're working -/// with is "bad" and you cannot use `ioctl_write!()` directly. -/// -/// The read/write direction is relative to userland, so this -/// command would be userland is writing and the kernel is -/// reading. -#[macro_export(local_inner_macros)] -macro_rules! request_code_write { - ($g:expr, $n:expr, $len:expr) => { - ioc!($crate::sys::ioctl::IN, $g, $n, $len) - }; -} - -/// Generate an ioctl request code for a command that reads and writes. -/// -/// This is equivalent to the `_IOWR()` macro exposed by the C ioctl API. -/// -/// You should only use this macro directly if the `ioctl` you're working -/// with is "bad" and you cannot use `ioctl_readwrite!()` directly. -#[macro_export(local_inner_macros)] -macro_rules! request_code_readwrite { - ($g:expr, $n:expr, $len:expr) => { - ioc!($crate::sys::ioctl::INOUT, $g, $n, $len) - }; -} diff --git a/vendor/nix/src/sys/ioctl/linux.rs b/vendor/nix/src/sys/ioctl/linux.rs deleted file mode 100644 index 0c0a20905..000000000 --- a/vendor/nix/src/sys/ioctl/linux.rs +++ /dev/null @@ -1,172 +0,0 @@ -/// The datatype used for the ioctl number -#[cfg(any(target_os = "android", target_env = "musl"))] -#[doc(hidden)] -pub type ioctl_num_type = ::libc::c_int; -#[cfg(not(any(target_os = "android", target_env = "musl")))] -#[doc(hidden)] -pub type ioctl_num_type = ::libc::c_ulong; -/// The datatype used for the 3rd argument -#[doc(hidden)] -pub type ioctl_param_type = ::libc::c_ulong; - -#[doc(hidden)] -pub const NRBITS: ioctl_num_type = 8; -#[doc(hidden)] -pub const TYPEBITS: ioctl_num_type = 8; - -#[cfg(any( - target_arch = "mips", - target_arch = "mips64", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "sparc64" -))] -mod consts { - #[doc(hidden)] - pub const NONE: u8 = 1; - #[doc(hidden)] - pub const READ: u8 = 2; - #[doc(hidden)] - pub const WRITE: u8 = 4; - #[doc(hidden)] - pub const SIZEBITS: u8 = 13; - #[doc(hidden)] - pub const DIRBITS: u8 = 3; -} - -// "Generic" ioctl protocol -#[cfg(any( - target_arch = "x86", - target_arch = "arm", - target_arch = "s390x", - target_arch = "x86_64", - target_arch = "aarch64", - target_arch = "riscv32", - target_arch = "riscv64" -))] -mod consts { - #[doc(hidden)] - pub const NONE: u8 = 0; - #[doc(hidden)] - pub const READ: u8 = 2; - #[doc(hidden)] - pub const WRITE: u8 = 1; - #[doc(hidden)] - pub const SIZEBITS: u8 = 14; - #[doc(hidden)] - pub const DIRBITS: u8 = 2; -} - -pub use self::consts::*; - -#[doc(hidden)] -pub const NRSHIFT: ioctl_num_type = 0; -#[doc(hidden)] -pub const TYPESHIFT: ioctl_num_type = NRSHIFT + NRBITS as ioctl_num_type; -#[doc(hidden)] -pub const SIZESHIFT: ioctl_num_type = TYPESHIFT + TYPEBITS as ioctl_num_type; -#[doc(hidden)] -pub const DIRSHIFT: ioctl_num_type = SIZESHIFT + SIZEBITS as ioctl_num_type; - -#[doc(hidden)] -pub const NRMASK: ioctl_num_type = (1 << NRBITS) - 1; -#[doc(hidden)] -pub const TYPEMASK: ioctl_num_type = (1 << TYPEBITS) - 1; -#[doc(hidden)] -pub const SIZEMASK: ioctl_num_type = (1 << SIZEBITS) - 1; -#[doc(hidden)] -pub const DIRMASK: ioctl_num_type = (1 << DIRBITS) - 1; - -/// Encode an ioctl command. -#[macro_export] -#[doc(hidden)] -macro_rules! ioc { - ($dir:expr, $ty:expr, $nr:expr, $sz:expr) => { - (($dir as $crate::sys::ioctl::ioctl_num_type - & $crate::sys::ioctl::DIRMASK) - << $crate::sys::ioctl::DIRSHIFT) - | (($ty as $crate::sys::ioctl::ioctl_num_type - & $crate::sys::ioctl::TYPEMASK) - << $crate::sys::ioctl::TYPESHIFT) - | (($nr as $crate::sys::ioctl::ioctl_num_type - & $crate::sys::ioctl::NRMASK) - << $crate::sys::ioctl::NRSHIFT) - | (($sz as $crate::sys::ioctl::ioctl_num_type - & $crate::sys::ioctl::SIZEMASK) - << $crate::sys::ioctl::SIZESHIFT) - }; -} - -/// Generate an ioctl request code for a command that passes no data. -/// -/// This is equivalent to the `_IO()` macro exposed by the C ioctl API. -/// -/// You should only use this macro directly if the `ioctl` you're working -/// with is "bad" and you cannot use `ioctl_none!()` directly. -/// -/// # Example -/// -/// ``` -/// # #[macro_use] extern crate nix; -/// const KVMIO: u8 = 0xAE; -/// ioctl_write_int_bad!(kvm_create_vm, request_code_none!(KVMIO, 0x03)); -/// # fn main() {} -/// ``` -#[macro_export(local_inner_macros)] -macro_rules! request_code_none { - ($ty:expr, $nr:expr) => { - ioc!($crate::sys::ioctl::NONE, $ty, $nr, 0) - }; -} - -/// Generate an ioctl request code for a command that reads. -/// -/// This is equivalent to the `_IOR()` macro exposed by the C ioctl API. -/// -/// You should only use this macro directly if the `ioctl` you're working -/// with is "bad" and you cannot use `ioctl_read!()` directly. -/// -/// The read/write direction is relative to userland, so this -/// command would be userland is reading and the kernel is -/// writing. -#[macro_export(local_inner_macros)] -macro_rules! request_code_read { - ($ty:expr, $nr:expr, $sz:expr) => { - ioc!($crate::sys::ioctl::READ, $ty, $nr, $sz) - }; -} - -/// Generate an ioctl request code for a command that writes. -/// -/// This is equivalent to the `_IOW()` macro exposed by the C ioctl API. -/// -/// You should only use this macro directly if the `ioctl` you're working -/// with is "bad" and you cannot use `ioctl_write!()` directly. -/// -/// The read/write direction is relative to userland, so this -/// command would be userland is writing and the kernel is -/// reading. -#[macro_export(local_inner_macros)] -macro_rules! request_code_write { - ($ty:expr, $nr:expr, $sz:expr) => { - ioc!($crate::sys::ioctl::WRITE, $ty, $nr, $sz) - }; -} - -/// Generate an ioctl request code for a command that reads and writes. -/// -/// This is equivalent to the `_IOWR()` macro exposed by the C ioctl API. -/// -/// You should only use this macro directly if the `ioctl` you're working -/// with is "bad" and you cannot use `ioctl_readwrite!()` directly. -#[macro_export(local_inner_macros)] -macro_rules! request_code_readwrite { - ($ty:expr, $nr:expr, $sz:expr) => { - ioc!( - $crate::sys::ioctl::READ | $crate::sys::ioctl::WRITE, - $ty, - $nr, - $sz - ) - }; -} diff --git a/vendor/nix/src/sys/ioctl/mod.rs b/vendor/nix/src/sys/ioctl/mod.rs deleted file mode 100644 index 98d6b5c99..000000000 --- a/vendor/nix/src/sys/ioctl/mod.rs +++ /dev/null @@ -1,786 +0,0 @@ -//! Provide helpers for making ioctl system calls. -//! -//! This library is pretty low-level and messy. `ioctl` is not fun. -//! -//! What is an `ioctl`? -//! =================== -//! -//! The `ioctl` syscall is the grab-bag syscall on POSIX systems. Don't want to add a new -//! syscall? Make it an `ioctl`! `ioctl` refers to both the syscall, and the commands that can be -//! sent with it. `ioctl` stands for "IO control", and the commands are always sent to a file -//! descriptor. -//! -//! It is common to see `ioctl`s used for the following purposes: -//! -//! * Provide read/write access to out-of-band data related to a device such as configuration -//! (for instance, setting serial port options) -//! * Provide a mechanism for performing full-duplex data transfers (for instance, xfer on SPI -//! devices). -//! * Provide access to control functions on a device (for example, on Linux you can send -//! commands like pause, resume, and eject to the CDROM device. -//! * Do whatever else the device driver creator thought made most sense. -//! -//! `ioctl`s are synchronous system calls and are similar to read and write calls in that regard. -//! They operate on file descriptors and have an identifier that specifies what the ioctl is. -//! Additionally they may read or write data and therefore need to pass along a data pointer. -//! Besides the semantics of the ioctls being confusing, the generation of this identifer can also -//! be difficult. -//! -//! Historically `ioctl` numbers were arbitrary hard-coded values. In Linux (before 2.6) and some -//! unices this has changed to a more-ordered system where the ioctl numbers are partitioned into -//! subcomponents (For linux this is documented in -//! [`Documentation/ioctl/ioctl-number.rst`](https://elixir.bootlin.com/linux/latest/source/Documentation/userspace-api/ioctl/ioctl-number.rst)): -//! -//! * Number: The actual ioctl ID -//! * Type: A grouping of ioctls for a common purpose or driver -//! * Size: The size in bytes of the data that will be transferred -//! * Direction: Whether there is any data and if it's read, write, or both -//! -//! Newer drivers should not generate complete integer identifiers for their `ioctl`s instead -//! preferring to use the 4 components above to generate the final ioctl identifier. Because of -//! how old `ioctl`s are, however, there are many hard-coded `ioctl` identifiers. These are -//! commonly referred to as "bad" in `ioctl` documentation. -//! -//! Defining `ioctl`s -//! ================= -//! -//! This library provides several `ioctl_*!` macros for binding `ioctl`s. These generate public -//! unsafe functions that can then be used for calling the ioctl. This macro has a few different -//! ways it can be used depending on the specific ioctl you're working with. -//! -//! A simple `ioctl` is `SPI_IOC_RD_MODE`. This ioctl works with the SPI interface on Linux. This -//! specific `ioctl` reads the mode of the SPI device as a `u8`. It's declared in -//! `/include/uapi/linux/spi/spidev.h` as `_IOR(SPI_IOC_MAGIC, 1, __u8)`. Since it uses the `_IOR` -//! macro, we know it's a `read` ioctl and can use the `ioctl_read!` macro as follows: -//! -//! ``` -//! # #[macro_use] extern crate nix; -//! const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h -//! const SPI_IOC_TYPE_MODE: u8 = 1; -//! ioctl_read!(spi_read_mode, SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, u8); -//! # fn main() {} -//! ``` -//! -//! This generates the function: -//! -//! ``` -//! # #[macro_use] extern crate nix; -//! # use std::mem; -//! # use nix::{libc, Result}; -//! # use nix::errno::Errno; -//! # use nix::libc::c_int as c_int; -//! # const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h -//! # const SPI_IOC_TYPE_MODE: u8 = 1; -//! pub unsafe fn spi_read_mode(fd: c_int, data: *mut u8) -> Result<c_int> { -//! let res = libc::ioctl(fd, request_code_read!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, mem::size_of::<u8>()), data); -//! Errno::result(res) -//! } -//! # fn main() {} -//! ``` -//! -//! The return value for the wrapper functions generated by the `ioctl_*!` macros are `nix::Error`s. -//! These are generated by assuming the return value of the ioctl is `-1` on error and everything -//! else is a valid return value. If this is not the case, `Result::map` can be used to map some -//! of the range of "good" values (-Inf..-2, 0..Inf) into a smaller range in a helper function. -//! -//! Writing `ioctl`s generally use pointers as their data source and these should use the -//! `ioctl_write_ptr!`. But in some cases an `int` is passed directly. For these `ioctl`s use the -//! `ioctl_write_int!` macro. This variant does not take a type as the last argument: -//! -//! ``` -//! # #[macro_use] extern crate nix; -//! const HCI_IOC_MAGIC: u8 = b'k'; -//! const HCI_IOC_HCIDEVUP: u8 = 1; -//! ioctl_write_int!(hci_dev_up, HCI_IOC_MAGIC, HCI_IOC_HCIDEVUP); -//! # fn main() {} -//! ``` -//! -//! Some `ioctl`s don't transfer any data, and those should use `ioctl_none!`. This macro -//! doesn't take a type and so it is declared similar to the `write_int` variant shown above. -//! -//! The mode for a given `ioctl` should be clear from the documentation if it has good -//! documentation. Otherwise it will be clear based on the macro used to generate the `ioctl` -//! number where `_IO`, `_IOR`, `_IOW`, and `_IOWR` map to "none", "read", "write_*", and "readwrite" -//! respectively. To determine the specific `write_` variant to use you'll need to find -//! what the argument type is supposed to be. If it's an `int`, then `write_int` should be used, -//! otherwise it should be a pointer and `write_ptr` should be used. On Linux the -//! [`ioctl_list` man page](https://man7.org/linux/man-pages/man2/ioctl_list.2.html) describes a -//! large number of `ioctl`s and describes their argument data type. -//! -//! Using "bad" `ioctl`s -//! -------------------- -//! -//! As mentioned earlier, there are many old `ioctl`s that do not use the newer method of -//! generating `ioctl` numbers and instead use hardcoded values. These can be used with the -//! `ioctl_*_bad!` macros. This naming comes from the Linux kernel which refers to these -//! `ioctl`s as "bad". These are a different variant as they bypass calling the macro that generates -//! the ioctl number and instead use the defined value directly. -//! -//! For example the `TCGETS` `ioctl` reads a `termios` data structure for a given file descriptor. -//! It's defined as `0x5401` in `ioctls.h` on Linux and can be implemented as: -//! -//! ``` -//! # #[macro_use] extern crate nix; -//! # #[cfg(any(target_os = "android", target_os = "linux"))] -//! # use nix::libc::TCGETS as TCGETS; -//! # #[cfg(any(target_os = "android", target_os = "linux"))] -//! # use nix::libc::termios as termios; -//! # #[cfg(any(target_os = "android", target_os = "linux"))] -//! ioctl_read_bad!(tcgets, TCGETS, termios); -//! # fn main() {} -//! ``` -//! -//! The generated function has the same form as that generated by `ioctl_read!`: -//! -//! ```text -//! pub unsafe fn tcgets(fd: c_int, data: *mut termios) -> Result<c_int>; -//! ``` -//! -//! Working with Arrays -//! ------------------- -//! -//! Some `ioctl`s work with entire arrays of elements. These are supported by the `ioctl_*_buf` -//! family of macros: `ioctl_read_buf`, `ioctl_write_buf`, and `ioctl_readwrite_buf`. Note that -//! there are no "bad" versions for working with buffers. The generated functions include a `len` -//! argument to specify the number of elements (where the type of each element is specified in the -//! macro). -//! -//! Again looking to the SPI `ioctl`s on Linux for an example, there is a `SPI_IOC_MESSAGE` `ioctl` -//! that queues up multiple SPI messages by writing an entire array of `spi_ioc_transfer` structs. -//! `linux/spi/spidev.h` defines a macro to calculate the `ioctl` number like: -//! -//! ```C -//! #define SPI_IOC_MAGIC 'k' -//! #define SPI_MSGSIZE(N) ... -//! #define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)]) -//! ``` -//! -//! The `SPI_MSGSIZE(N)` calculation is already handled by the `ioctl_*!` macros, so all that's -//! needed to define this `ioctl` is: -//! -//! ``` -//! # #[macro_use] extern crate nix; -//! const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h -//! const SPI_IOC_TYPE_MESSAGE: u8 = 0; -//! # pub struct spi_ioc_transfer(u64); -//! ioctl_write_buf!(spi_transfer, SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, spi_ioc_transfer); -//! # fn main() {} -//! ``` -//! -//! This generates a function like: -//! -//! ``` -//! # #[macro_use] extern crate nix; -//! # use std::mem; -//! # use nix::{libc, Result}; -//! # use nix::errno::Errno; -//! # use nix::libc::c_int as c_int; -//! # const SPI_IOC_MAGIC: u8 = b'k'; -//! # const SPI_IOC_TYPE_MESSAGE: u8 = 0; -//! # pub struct spi_ioc_transfer(u64); -//! pub unsafe fn spi_message(fd: c_int, data: &mut [spi_ioc_transfer]) -> Result<c_int> { -//! let res = libc::ioctl(fd, -//! request_code_write!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, data.len() * mem::size_of::<spi_ioc_transfer>()), -//! data); -//! Errno::result(res) -//! } -//! # fn main() {} -//! ``` -//! -//! Finding `ioctl` Documentation -//! ----------------------------- -//! -//! For Linux, look at your system's headers. For example, `/usr/include/linux/input.h` has a lot -//! of lines defining macros which use `_IO`, `_IOR`, `_IOW`, `_IOC`, and `_IOWR`. Some `ioctl`s are -//! documented directly in the headers defining their constants, but others have more extensive -//! documentation in man pages (like termios' `ioctl`s which are in `tty_ioctl(4)`). -//! -//! Documenting the Generated Functions -//! =================================== -//! -//! In many cases, users will wish for the functions generated by the `ioctl` -//! macro to be public and documented. For this reason, the generated functions -//! are public by default. If you wish to hide the ioctl, you will need to put -//! them in a private module. -//! -//! For documentation, it is possible to use doc comments inside the `ioctl_*!` macros. Here is an -//! example : -//! -//! ``` -//! # #[macro_use] extern crate nix; -//! # use nix::libc::c_int; -//! ioctl_read! { -//! /// Make the given terminal the controlling terminal of the calling process. The calling -//! /// process must be a session leader and not have a controlling terminal already. If the -//! /// terminal is already the controlling terminal of a different session group then the -//! /// ioctl will fail with **EPERM**, unless the caller is root (more precisely: has the -//! /// **CAP_SYS_ADMIN** capability) and arg equals 1, in which case the terminal is stolen -//! /// and all processes that had it as controlling terminal lose it. -//! tiocsctty, b't', 19, c_int -//! } -//! -//! # fn main() {} -//! ``` -use cfg_if::cfg_if; - -#[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] -#[macro_use] -mod linux; - -#[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "redox" -))] -pub use self::linux::*; - -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "haiku", - target_os = "openbsd" -))] -#[macro_use] -mod bsd; - -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "haiku", - target_os = "openbsd" -))] -pub use self::bsd::*; - -/// Convert raw ioctl return value to a Nix result -#[macro_export] -#[doc(hidden)] -macro_rules! convert_ioctl_res { - ($w:expr) => {{ - $crate::errno::Errno::result($w) - }}; -} - -/// Generates a wrapper function for an ioctl that passes no data to the kernel. -/// -/// The arguments to this macro are: -/// -/// * The function name -/// * The ioctl identifier -/// * The ioctl sequence number -/// -/// The generated function has the following signature: -/// -/// ```rust,ignore -/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int) -> Result<libc::c_int> -/// ``` -/// -/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). -/// -/// # Example -/// -/// The `videodev2` driver on Linux defines the `log_status` `ioctl` as: -/// -/// ```C -/// #define VIDIOC_LOG_STATUS _IO('V', 70) -/// ``` -/// -/// This can be implemented in Rust like: -/// -/// ```no_run -/// # #[macro_use] extern crate nix; -/// ioctl_none!(log_status, b'V', 70); -/// fn main() {} -/// ``` -#[macro_export(local_inner_macros)] -macro_rules! ioctl_none { - ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr) => ( - $(#[$attr])* - pub unsafe fn $name(fd: $crate::libc::c_int) - -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, request_code_none!($ioty, $nr) as $crate::sys::ioctl::ioctl_num_type)) - } - ) -} - -/// Generates a wrapper function for a "bad" ioctl that passes no data to the kernel. -/// -/// The arguments to this macro are: -/// -/// * The function name -/// * The ioctl request code -/// -/// The generated function has the following signature: -/// -/// ```rust,ignore -/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int) -> Result<libc::c_int> -/// ``` -/// -/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). -/// -/// # Example -/// -/// ```no_run -/// # #[macro_use] extern crate nix; -/// # use libc::TIOCNXCL; -/// # use std::fs::File; -/// # use std::os::unix::io::AsRawFd; -/// ioctl_none_bad!(tiocnxcl, TIOCNXCL); -/// fn main() { -/// let file = File::open("/dev/ttyUSB0").unwrap(); -/// unsafe { tiocnxcl(file.as_raw_fd()) }.unwrap(); -/// } -/// ``` -// TODO: add an example using request_code_*!() -#[macro_export(local_inner_macros)] -macro_rules! ioctl_none_bad { - ($(#[$attr:meta])* $name:ident, $nr:expr) => ( - $(#[$attr])* - pub unsafe fn $name(fd: $crate::libc::c_int) - -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type)) - } - ) -} - -/// Generates a wrapper function for an ioctl that reads data from the kernel. -/// -/// The arguments to this macro are: -/// -/// * The function name -/// * The ioctl identifier -/// * The ioctl sequence number -/// * The data type passed by this ioctl -/// -/// The generated function has the following signature: -/// -/// ```rust,ignore -/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result<libc::c_int> -/// ``` -/// -/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). -/// -/// # Example -/// -/// ``` -/// # #[macro_use] extern crate nix; -/// const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h -/// const SPI_IOC_TYPE_MODE: u8 = 1; -/// ioctl_read!(spi_read_mode, SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, u8); -/// # fn main() {} -/// ``` -#[macro_export(local_inner_macros)] -macro_rules! ioctl_read { - ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => ( - $(#[$attr])* - pub unsafe fn $name(fd: $crate::libc::c_int, - data: *mut $ty) - -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data)) - } - ) -} - -/// Generates a wrapper function for a "bad" ioctl that reads data from the kernel. -/// -/// The arguments to this macro are: -/// -/// * The function name -/// * The ioctl request code -/// * The data type passed by this ioctl -/// -/// The generated function has the following signature: -/// -/// ```rust,ignore -/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result<libc::c_int> -/// ``` -/// -/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). -/// -/// # Example -/// -/// ``` -/// # #[macro_use] extern crate nix; -/// # #[cfg(any(target_os = "android", target_os = "linux"))] -/// ioctl_read_bad!(tcgets, libc::TCGETS, libc::termios); -/// # fn main() {} -/// ``` -#[macro_export(local_inner_macros)] -macro_rules! ioctl_read_bad { - ($(#[$attr:meta])* $name:ident, $nr:expr, $ty:ty) => ( - $(#[$attr])* - pub unsafe fn $name(fd: $crate::libc::c_int, - data: *mut $ty) - -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data)) - } - ) -} - -/// Generates a wrapper function for an ioctl that writes data through a pointer to the kernel. -/// -/// The arguments to this macro are: -/// -/// * The function name -/// * The ioctl identifier -/// * The ioctl sequence number -/// * The data type passed by this ioctl -/// -/// The generated function has the following signature: -/// -/// ```rust,ignore -/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *const DATA_TYPE) -> Result<libc::c_int> -/// ``` -/// -/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). -/// -/// # Example -/// -/// ``` -/// # #[macro_use] extern crate nix; -/// # pub struct v4l2_audio {} -/// ioctl_write_ptr!(s_audio, b'V', 34, v4l2_audio); -/// # fn main() {} -/// ``` -#[macro_export(local_inner_macros)] -macro_rules! ioctl_write_ptr { - ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => ( - $(#[$attr])* - pub unsafe fn $name(fd: $crate::libc::c_int, - data: *const $ty) - -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data)) - } - ) -} - -/// Generates a wrapper function for a "bad" ioctl that writes data through a pointer to the kernel. -/// -/// The arguments to this macro are: -/// -/// * The function name -/// * The ioctl request code -/// * The data type passed by this ioctl -/// -/// The generated function has the following signature: -/// -/// ```rust,ignore -/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *const DATA_TYPE) -> Result<libc::c_int> -/// ``` -/// -/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). -/// -/// # Example -/// -/// ``` -/// # #[macro_use] extern crate nix; -/// # #[cfg(any(target_os = "android", target_os = "linux"))] -/// ioctl_write_ptr_bad!(tcsets, libc::TCSETS, libc::termios); -/// # fn main() {} -/// ``` -#[macro_export(local_inner_macros)] -macro_rules! ioctl_write_ptr_bad { - ($(#[$attr:meta])* $name:ident, $nr:expr, $ty:ty) => ( - $(#[$attr])* - pub unsafe fn $name(fd: $crate::libc::c_int, - data: *const $ty) - -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data)) - } - ) -} - -cfg_if! { - if #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] { - /// Generates a wrapper function for a ioctl that writes an integer to the kernel. - /// - /// The arguments to this macro are: - /// - /// * The function name - /// * The ioctl identifier - /// * The ioctl sequence number - /// - /// The generated function has the following signature: - /// - /// ```rust,ignore - /// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: nix::sys::ioctl::ioctl_param_type) -> Result<libc::c_int> - /// ``` - /// - /// `nix::sys::ioctl::ioctl_param_type` depends on the OS: - /// * BSD - `libc::c_int` - /// * Linux - `libc::c_ulong` - /// - /// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). - /// - /// # Example - /// - /// ``` - /// # #[macro_use] extern crate nix; - /// ioctl_write_int!(vt_activate, b'v', 4); - /// # fn main() {} - /// ``` - #[macro_export(local_inner_macros)] - macro_rules! ioctl_write_int { - ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr) => ( - $(#[$attr])* - pub unsafe fn $name(fd: $crate::libc::c_int, - data: $crate::sys::ioctl::ioctl_param_type) - -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write_int!($ioty, $nr) as $crate::sys::ioctl::ioctl_num_type, data)) - } - ) - } - } else { - /// Generates a wrapper function for a ioctl that writes an integer to the kernel. - /// - /// The arguments to this macro are: - /// - /// * The function name - /// * The ioctl identifier - /// * The ioctl sequence number - /// - /// The generated function has the following signature: - /// - /// ```rust,ignore - /// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: nix::sys::ioctl::ioctl_param_type) -> Result<libc::c_int> - /// ``` - /// - /// `nix::sys::ioctl::ioctl_param_type` depends on the OS: - /// * BSD - `libc::c_int` - /// * Linux - `libc::c_ulong` - /// - /// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). - /// - /// # Example - /// - /// ``` - /// # #[macro_use] extern crate nix; - /// const HCI_IOC_MAGIC: u8 = b'k'; - /// const HCI_IOC_HCIDEVUP: u8 = 1; - /// ioctl_write_int!(hci_dev_up, HCI_IOC_MAGIC, HCI_IOC_HCIDEVUP); - /// # fn main() {} - /// ``` - #[macro_export(local_inner_macros)] - macro_rules! ioctl_write_int { - ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr) => ( - $(#[$attr])* - pub unsafe fn $name(fd: $crate::libc::c_int, - data: $crate::sys::ioctl::ioctl_param_type) - -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of::<$crate::libc::c_int>()) as $crate::sys::ioctl::ioctl_num_type, data)) - } - ) - } - } -} - -/// Generates a wrapper function for a "bad" ioctl that writes an integer to the kernel. -/// -/// The arguments to this macro are: -/// -/// * The function name -/// * The ioctl request code -/// -/// The generated function has the following signature: -/// -/// ```rust,ignore -/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: libc::c_int) -> Result<libc::c_int> -/// ``` -/// -/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). -/// -/// # Examples -/// -/// ``` -/// # #[macro_use] extern crate nix; -/// # #[cfg(any(target_os = "android", target_os = "linux"))] -/// ioctl_write_int_bad!(tcsbrk, libc::TCSBRK); -/// # fn main() {} -/// ``` -/// -/// ```rust -/// # #[macro_use] extern crate nix; -/// const KVMIO: u8 = 0xAE; -/// ioctl_write_int_bad!(kvm_create_vm, request_code_none!(KVMIO, 0x03)); -/// # fn main() {} -/// ``` -#[macro_export(local_inner_macros)] -macro_rules! ioctl_write_int_bad { - ($(#[$attr:meta])* $name:ident, $nr:expr) => ( - $(#[$attr])* - pub unsafe fn $name(fd: $crate::libc::c_int, - data: $crate::libc::c_int) - -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data)) - } - ) -} - -/// Generates a wrapper function for an ioctl that reads and writes data to the kernel. -/// -/// The arguments to this macro are: -/// -/// * The function name -/// * The ioctl identifier -/// * The ioctl sequence number -/// * The data type passed by this ioctl -/// -/// The generated function has the following signature: -/// -/// ```rust,ignore -/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result<libc::c_int> -/// ``` -/// -/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). -/// -/// # Example -/// -/// ``` -/// # #[macro_use] extern crate nix; -/// # pub struct v4l2_audio {} -/// ioctl_readwrite!(enum_audio, b'V', 65, v4l2_audio); -/// # fn main() {} -/// ``` -#[macro_export(local_inner_macros)] -macro_rules! ioctl_readwrite { - ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => ( - $(#[$attr])* - pub unsafe fn $name(fd: $crate::libc::c_int, - data: *mut $ty) - -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data)) - } - ) -} - -/// Generates a wrapper function for a "bad" ioctl that reads and writes data to the kernel. -/// -/// The arguments to this macro are: -/// -/// * The function name -/// * The ioctl request code -/// * The data type passed by this ioctl -/// -/// The generated function has the following signature: -/// -/// ```rust,ignore -/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result<libc::c_int> -/// ``` -/// -/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). -// TODO: Find an example for ioctl_readwrite_bad -#[macro_export(local_inner_macros)] -macro_rules! ioctl_readwrite_bad { - ($(#[$attr:meta])* $name:ident, $nr:expr, $ty:ty) => ( - $(#[$attr])* - pub unsafe fn $name(fd: $crate::libc::c_int, - data: *mut $ty) - -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data)) - } - ) -} - -/// Generates a wrapper function for an ioctl that reads an array of elements from the kernel. -/// -/// The arguments to this macro are: -/// -/// * The function name -/// * The ioctl identifier -/// * The ioctl sequence number -/// * The data type passed by this ioctl -/// -/// The generated function has the following signature: -/// -/// ```rust,ignore -/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: &mut [DATA_TYPE]) -> Result<libc::c_int> -/// ``` -/// -/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). -// TODO: Find an example for ioctl_read_buf -#[macro_export(local_inner_macros)] -macro_rules! ioctl_read_buf { - ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => ( - $(#[$attr])* - pub unsafe fn $name(fd: $crate::libc::c_int, - data: &mut [$ty]) - -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data)) - } - ) -} - -/// Generates a wrapper function for an ioctl that writes an array of elements to the kernel. -/// -/// The arguments to this macro are: -/// -/// * The function name -/// * The ioctl identifier -/// * The ioctl sequence number -/// * The data type passed by this ioctl -/// -/// The generated function has the following signature: -/// -/// ```rust,ignore -/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: &[DATA_TYPE]) -> Result<libc::c_int> -/// ``` -/// -/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). -/// -/// # Examples -/// -/// ``` -/// # #[macro_use] extern crate nix; -/// const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h -/// const SPI_IOC_TYPE_MESSAGE: u8 = 0; -/// # pub struct spi_ioc_transfer(u64); -/// ioctl_write_buf!(spi_transfer, SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, spi_ioc_transfer); -/// # fn main() {} -/// ``` -#[macro_export(local_inner_macros)] -macro_rules! ioctl_write_buf { - ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => ( - $(#[$attr])* - pub unsafe fn $name(fd: $crate::libc::c_int, - data: &[$ty]) - -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data)) - } - ) -} - -/// Generates a wrapper function for an ioctl that reads and writes an array of elements to the kernel. -/// -/// The arguments to this macro are: -/// -/// * The function name -/// * The ioctl identifier -/// * The ioctl sequence number -/// * The data type passed by this ioctl -/// -/// The generated function has the following signature: -/// -/// ```rust,ignore -/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: &mut [DATA_TYPE]) -> Result<libc::c_int> -/// ``` -/// -/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). -// TODO: Find an example for readwrite_buf -#[macro_export(local_inner_macros)] -macro_rules! ioctl_readwrite_buf { - ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => ( - $(#[$attr])* - pub unsafe fn $name(fd: $crate::libc::c_int, - data: &mut [$ty]) - -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data)) - } - ) -} diff --git a/vendor/nix/src/sys/memfd.rs b/vendor/nix/src/sys/memfd.rs deleted file mode 100644 index ad9345e89..000000000 --- a/vendor/nix/src/sys/memfd.rs +++ /dev/null @@ -1,64 +0,0 @@ -//! Interfaces for managing memory-backed files. - -use cfg_if::cfg_if; -use std::os::unix::io::RawFd; - -use crate::errno::Errno; -use crate::Result; -use std::ffi::CStr; - -libc_bitflags!( - /// Options that change the behavior of [`memfd_create`]. - pub struct MemFdCreateFlag: libc::c_uint { - /// Set the close-on-exec ([`FD_CLOEXEC`]) flag on the new file descriptor. - /// - /// By default, the new file descriptor is set to remain open across an [`execve`] - /// (the `FD_CLOEXEC` flag is initially disabled). This flag can be used to change - /// this default. The file offset is set to the beginning of the file (see [`lseek`]). - /// - /// See also the description of the `O_CLOEXEC` flag in [`open(2)`]. - /// - /// [`execve`]: crate::unistd::execve - /// [`lseek`]: crate::unistd::lseek - /// [`FD_CLOEXEC`]: crate::fcntl::FdFlag::FD_CLOEXEC - /// [`open(2)`]: https://man7.org/linux/man-pages/man2/open.2.html - MFD_CLOEXEC; - /// Allow sealing operations on this file. - /// - /// See also the file sealing notes given in [`memfd_create(2)`]. - /// - /// [`memfd_create(2)`]: https://man7.org/linux/man-pages/man2/memfd_create.2.html - MFD_ALLOW_SEALING; - } -); - -/// Creates an anonymous file that lives in memory, and return a file-descriptor to it. -/// -/// The file behaves like a regular file, and so can be modified, truncated, memory-mapped, and so on. -/// However, unlike a regular file, it lives in RAM and has a volatile backing storage. -/// -/// For more information, see [`memfd_create(2)`]. -/// -/// [`memfd_create(2)`]: https://man7.org/linux/man-pages/man2/memfd_create.2.html -pub fn memfd_create(name: &CStr, flags: MemFdCreateFlag) -> Result<RawFd> { - let res = unsafe { - cfg_if! { - if #[cfg(all( - // Android does not have a memfd_create symbol - not(target_os = "android"), - any( - target_os = "freebsd", - // If the OS is Linux, gnu and musl expose a memfd_create symbol but not uclibc - target_env = "gnu", - target_env = "musl", - )))] - { - libc::memfd_create(name.as_ptr(), flags.bits()) - } else { - libc::syscall(libc::SYS_memfd_create, name.as_ptr(), flags.bits()) - } - } - }; - - Errno::result(res).map(|r| r as RawFd) -} diff --git a/vendor/nix/src/sys/mman.rs b/vendor/nix/src/sys/mman.rs deleted file mode 100644 index 2bee09161..000000000 --- a/vendor/nix/src/sys/mman.rs +++ /dev/null @@ -1,599 +0,0 @@ -//! Memory management declarations. - -use crate::errno::Errno; -#[cfg(not(target_os = "android"))] -use crate::NixPath; -use crate::Result; -#[cfg(not(target_os = "android"))] -#[cfg(feature = "fs")] -use crate::{fcntl::OFlag, sys::stat::Mode}; -use libc::{self, c_int, c_void, off_t, size_t}; -use std::{os::unix::io::RawFd, num::NonZeroUsize}; - -libc_bitflags! { - /// Desired memory protection of a memory mapping. - pub struct ProtFlags: c_int { - /// Pages cannot be accessed. - PROT_NONE; - /// Pages can be read. - PROT_READ; - /// Pages can be written. - PROT_WRITE; - /// Pages can be executed - PROT_EXEC; - /// Apply protection up to the end of a mapping that grows upwards. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - PROT_GROWSDOWN; - /// Apply protection down to the beginning of a mapping that grows downwards. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - PROT_GROWSUP; - } -} - -libc_bitflags! { - /// Additional parameters for [`mmap`]. - pub struct MapFlags: c_int { - /// Compatibility flag. Ignored. - MAP_FILE; - /// Share this mapping. Mutually exclusive with `MAP_PRIVATE`. - MAP_SHARED; - /// Create a private copy-on-write mapping. Mutually exclusive with `MAP_SHARED`. - MAP_PRIVATE; - /// Place the mapping at exactly the address specified in `addr`. - MAP_FIXED; - /// Place the mapping at exactly the address specified in `addr`, but never clobber an existing range. - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_FIXED_NOREPLACE; - /// To be used with `MAP_FIXED`, to forbid the system - /// to select a different address than the one specified. - #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_EXCL; - /// Synonym for `MAP_ANONYMOUS`. - MAP_ANON; - /// The mapping is not backed by any file. - MAP_ANONYMOUS; - /// Put the mapping into the first 2GB of the process address space. - #[cfg(any(all(any(target_os = "android", target_os = "linux"), - any(target_arch = "x86", target_arch = "x86_64")), - all(target_os = "linux", target_env = "musl", any(target_arch = "x86", target_arch = "x86_64")), - all(target_os = "freebsd", target_pointer_width = "64")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_32BIT; - /// Used for stacks; indicates to the kernel that the mapping should extend downward in memory. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_GROWSDOWN; - /// Compatibility flag. Ignored. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_DENYWRITE; - /// Compatibility flag. Ignored. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_EXECUTABLE; - /// Mark the mmaped region to be locked in the same way as `mlock(2)`. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_LOCKED; - /// Do not reserve swap space for this mapping. - /// - /// This was removed in FreeBSD 11 and is unused in DragonFlyBSD. - #[cfg(not(any(target_os = "dragonfly", target_os = "freebsd")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_NORESERVE; - /// Populate page tables for a mapping. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_POPULATE; - /// Only meaningful when used with `MAP_POPULATE`. Don't perform read-ahead. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_NONBLOCK; - /// Allocate the mapping using "huge pages." - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_HUGETLB; - /// Make use of 64KB huge page (must be supported by the system) - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_HUGE_64KB; - /// Make use of 512KB huge page (must be supported by the system) - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_HUGE_512KB; - /// Make use of 1MB huge page (must be supported by the system) - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_HUGE_1MB; - /// Make use of 2MB huge page (must be supported by the system) - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_HUGE_2MB; - /// Make use of 8MB huge page (must be supported by the system) - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_HUGE_8MB; - /// Make use of 16MB huge page (must be supported by the system) - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_HUGE_16MB; - /// Make use of 32MB huge page (must be supported by the system) - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_HUGE_32MB; - /// Make use of 256MB huge page (must be supported by the system) - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_HUGE_256MB; - /// Make use of 512MB huge page (must be supported by the system) - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_HUGE_512MB; - /// Make use of 1GB huge page (must be supported by the system) - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_HUGE_1GB; - /// Make use of 2GB huge page (must be supported by the system) - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_HUGE_2GB; - /// Make use of 16GB huge page (must be supported by the system) - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_HUGE_16GB; - - /// Lock the mapped region into memory as with `mlock(2)`. - #[cfg(target_os = "netbsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_WIRED; - /// Causes dirtied data in the specified range to be flushed to disk only when necessary. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_NOSYNC; - /// Rename private pages to a file. - /// - /// This was removed in FreeBSD 11 and is unused in DragonFlyBSD. - #[cfg(any(target_os = "netbsd", target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_RENAME; - /// Region may contain semaphores. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_HASSEMAPHORE; - /// Region grows down, like a stack. - #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux", target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_STACK; - /// Pages in this mapping are not retained in the kernel's memory cache. - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_NOCACHE; - /// Allows the W/X bit on the page, it's necessary on aarch64 architecture. - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_JIT; - /// Allows to use large pages, underlying alignment based on size. - #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_ALIGNED_SUPER; - /// Pages will be discarded in the core dumps. - #[cfg(target_os = "openbsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_CONCEAL; - } -} - -#[cfg(any(target_os = "linux", target_os = "netbsd"))] -libc_bitflags! { - /// Options for [`mremap`]. - pub struct MRemapFlags: c_int { - /// Permit the kernel to relocate the mapping to a new virtual address, if necessary. - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MREMAP_MAYMOVE; - /// Place the mapping at exactly the address specified in `new_address`. - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MREMAP_FIXED; - /// Place the mapping at exactly the address specified in `new_address`. - #[cfg(target_os = "netbsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_FIXED; - /// Allows to duplicate the mapping to be able to apply different flags on the copy. - #[cfg(target_os = "netbsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MAP_REMAPDUP; - } -} - -libc_enum! { - /// Usage information for a range of memory to allow for performance optimizations by the kernel. - /// - /// Used by [`madvise`]. - #[repr(i32)] - #[non_exhaustive] - pub enum MmapAdvise { - /// No further special treatment. This is the default. - MADV_NORMAL, - /// Expect random page references. - MADV_RANDOM, - /// Expect sequential page references. - MADV_SEQUENTIAL, - /// Expect access in the near future. - MADV_WILLNEED, - /// Do not expect access in the near future. - MADV_DONTNEED, - /// Free up a given range of pages and its associated backing store. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_REMOVE, - /// Do not make pages in this range available to the child after a `fork(2)`. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_DONTFORK, - /// Undo the effect of `MADV_DONTFORK`. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_DOFORK, - /// Poison the given pages. - /// - /// Subsequent references to those pages are treated like hardware memory corruption. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_HWPOISON, - /// Enable Kernel Samepage Merging (KSM) for the given pages. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_MERGEABLE, - /// Undo the effect of `MADV_MERGEABLE` - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_UNMERGEABLE, - /// Preserve the memory of each page but offline the original page. - #[cfg(any(target_os = "android", - all(target_os = "linux", any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "s390x", - target_arch = "x86", - target_arch = "x86_64", - target_arch = "sparc64"))))] - MADV_SOFT_OFFLINE, - /// Enable Transparent Huge Pages (THP) for pages in the given range. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_HUGEPAGE, - /// Undo the effect of `MADV_HUGEPAGE`. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_NOHUGEPAGE, - /// Exclude the given range from a core dump. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_DONTDUMP, - /// Undo the effect of an earlier `MADV_DONTDUMP`. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_DODUMP, - /// Specify that the application no longer needs the pages in the given range. - MADV_FREE, - /// Request that the system not flush the current range to disk unless it needs to. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_NOSYNC, - /// Undoes the effects of `MADV_NOSYNC` for any future pages dirtied within the given range. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_AUTOSYNC, - /// Region is not included in a core file. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_NOCORE, - /// Include region in a core file - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_CORE, - /// This process should not be killed when swap space is exhausted. - #[cfg(any(target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_PROTECT, - /// Invalidate the hardware page table for the given region. - #[cfg(target_os = "dragonfly")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_INVAL, - /// Set the offset of the page directory page to `value` for the virtual page table. - #[cfg(target_os = "dragonfly")] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_SETMAP, - /// Indicates that the application will not need the data in the given range. - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_ZERO_WIRED_PAGES, - /// Pages can be reused (by anyone). - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_FREE_REUSABLE, - /// Caller wants to reuse those pages. - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MADV_FREE_REUSE, - // Darwin doesn't document this flag's behavior. - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - #[allow(missing_docs)] - MADV_CAN_REUSE, - } -} - -libc_bitflags! { - /// Configuration flags for [`msync`]. - pub struct MsFlags: c_int { - /// Schedule an update but return immediately. - MS_ASYNC; - /// Invalidate all cached data. - MS_INVALIDATE; - /// Invalidate pages, but leave them mapped. - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MS_KILLPAGES; - /// Deactivate pages, but leave them mapped. - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MS_DEACTIVATE; - /// Perform an update and wait for it to complete. - MS_SYNC; - } -} - -#[cfg(not(target_os = "haiku"))] -libc_bitflags! { - /// Flags for [`mlockall`]. - pub struct MlockAllFlags: c_int { - /// Lock pages that are currently mapped into the address space of the process. - MCL_CURRENT; - /// Lock pages which will become mapped into the address space of the process in the future. - MCL_FUTURE; - } -} - -/// Locks all memory pages that contain part of the address range with `length` -/// bytes starting at `addr`. -/// -/// Locked pages never move to the swap area. -/// -/// # Safety -/// -/// `addr` must meet all the requirements described in the [`mlock(2)`] man page. -/// -/// [`mlock(2)`]: https://man7.org/linux/man-pages/man2/mlock.2.html -pub unsafe fn mlock(addr: *const c_void, length: size_t) -> Result<()> { - Errno::result(libc::mlock(addr, length)).map(drop) -} - -/// Unlocks all memory pages that contain part of the address range with -/// `length` bytes starting at `addr`. -/// -/// # Safety -/// -/// `addr` must meet all the requirements described in the [`munlock(2)`] man -/// page. -/// -/// [`munlock(2)`]: https://man7.org/linux/man-pages/man2/munlock.2.html -pub unsafe fn munlock(addr: *const c_void, length: size_t) -> Result<()> { - Errno::result(libc::munlock(addr, length)).map(drop) -} - -/// Locks all memory pages mapped into this process' address space. -/// -/// Locked pages never move to the swap area. For more information, see [`mlockall(2)`]. -/// -/// [`mlockall(2)`]: https://man7.org/linux/man-pages/man2/mlockall.2.html -#[cfg(not(target_os = "haiku"))] -pub fn mlockall(flags: MlockAllFlags) -> Result<()> { - unsafe { Errno::result(libc::mlockall(flags.bits())) }.map(drop) -} - -/// Unlocks all memory pages mapped into this process' address space. -/// -/// For more information, see [`munlockall(2)`]. -/// -/// [`munlockall(2)`]: https://man7.org/linux/man-pages/man2/munlockall.2.html -#[cfg(not(target_os = "haiku"))] -pub fn munlockall() -> Result<()> { - unsafe { Errno::result(libc::munlockall()) }.map(drop) -} - -/// allocate memory, or map files or devices into memory -/// -/// # Safety -/// -/// See the [`mmap(2)`] man page for detailed requirements. -/// -/// [`mmap(2)`]: https://man7.org/linux/man-pages/man2/mmap.2.html -pub unsafe fn mmap( - addr: Option<NonZeroUsize>, - length: NonZeroUsize, - prot: ProtFlags, - flags: MapFlags, - fd: RawFd, - offset: off_t, -) -> Result<*mut c_void> { - let ptr = addr.map_or( - std::ptr::null_mut(), - |a| usize::from(a) as *mut c_void - ); - - let ret = libc::mmap(ptr, length.into(), prot.bits(), flags.bits(), fd, offset); - - if ret == libc::MAP_FAILED { - Err(Errno::last()) - } else { - Ok(ret) - } -} - -/// Expands (or shrinks) an existing memory mapping, potentially moving it at -/// the same time. -/// -/// # Safety -/// -/// See the `mremap(2)` [man page](https://man7.org/linux/man-pages/man2/mremap.2.html) for -/// detailed requirements. -#[cfg(any(target_os = "linux", target_os = "netbsd"))] -pub unsafe fn mremap( - addr: *mut c_void, - old_size: size_t, - new_size: size_t, - flags: MRemapFlags, - new_address: Option<*mut c_void>, -) -> Result<*mut c_void> { - #[cfg(target_os = "linux")] - let ret = libc::mremap( - addr, - old_size, - new_size, - flags.bits(), - new_address.unwrap_or(std::ptr::null_mut()), - ); - #[cfg(target_os = "netbsd")] - let ret = libc::mremap( - addr, - old_size, - new_address.unwrap_or(std::ptr::null_mut()), - new_size, - flags.bits(), - ); - - if ret == libc::MAP_FAILED { - Err(Errno::last()) - } else { - Ok(ret) - } -} - -/// remove a mapping -/// -/// # Safety -/// -/// `addr` must meet all the requirements described in the [`munmap(2)`] man -/// page. -/// -/// [`munmap(2)`]: https://man7.org/linux/man-pages/man2/munmap.2.html -pub unsafe fn munmap(addr: *mut c_void, len: size_t) -> Result<()> { - Errno::result(libc::munmap(addr, len)).map(drop) -} - -/// give advice about use of memory -/// -/// # Safety -/// -/// See the [`madvise(2)`] man page. Take special care when using -/// [`MmapAdvise::MADV_FREE`]. -/// -/// [`madvise(2)`]: https://man7.org/linux/man-pages/man2/madvise.2.html -pub unsafe fn madvise( - addr: *mut c_void, - length: size_t, - advise: MmapAdvise, -) -> Result<()> { - Errno::result(libc::madvise(addr, length, advise as i32)).map(drop) -} - -/// Set protection of memory mapping. -/// -/// See [`mprotect(3)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mprotect.html) for -/// details. -/// -/// # Safety -/// -/// Calls to `mprotect` are inherently unsafe, as changes to memory protections can lead to -/// SIGSEGVs. -/// -/// ``` -/// # use nix::libc::size_t; -/// # use nix::sys::mman::{mmap, mprotect, MapFlags, ProtFlags}; -/// # use std::ptr; -/// const ONE_K: size_t = 1024; -/// let one_k_non_zero = std::num::NonZeroUsize::new(ONE_K).unwrap(); -/// let mut slice: &mut [u8] = unsafe { -/// let mem = mmap(None, one_k_non_zero, ProtFlags::PROT_NONE, -/// MapFlags::MAP_ANON | MapFlags::MAP_PRIVATE, -1, 0).unwrap(); -/// mprotect(mem, ONE_K, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE).unwrap(); -/// std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K) -/// }; -/// assert_eq!(slice[0], 0x00); -/// slice[0] = 0xFF; -/// assert_eq!(slice[0], 0xFF); -/// ``` -pub unsafe fn mprotect( - addr: *mut c_void, - length: size_t, - prot: ProtFlags, -) -> Result<()> { - Errno::result(libc::mprotect(addr, length, prot.bits())).map(drop) -} - -/// synchronize a mapped region -/// -/// # Safety -/// -/// `addr` must meet all the requirements described in the [`msync(2)`] man -/// page. -/// -/// [`msync(2)`]: https://man7.org/linux/man-pages/man2/msync.2.html -pub unsafe fn msync( - addr: *mut c_void, - length: size_t, - flags: MsFlags, -) -> Result<()> { - Errno::result(libc::msync(addr, length, flags.bits())).map(drop) -} - -#[cfg(not(target_os = "android"))] -feature! { -#![feature = "fs"] -/// Creates and opens a new, or opens an existing, POSIX shared memory object. -/// -/// For more information, see [`shm_open(3)`]. -/// -/// [`shm_open(3)`]: https://man7.org/linux/man-pages/man3/shm_open.3.html -pub fn shm_open<P>( - name: &P, - flag: OFlag, - mode: Mode - ) -> Result<RawFd> - where P: ?Sized + NixPath -{ - let ret = name.with_nix_path(|cstr| { - #[cfg(any(target_os = "macos", target_os = "ios"))] - unsafe { - libc::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as libc::c_uint) - } - #[cfg(not(any(target_os = "macos", target_os = "ios")))] - unsafe { - libc::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as libc::mode_t) - } - })?; - - Errno::result(ret) -} -} - -/// Performs the converse of [`shm_open`], removing an object previously created. -/// -/// For more information, see [`shm_unlink(3)`]. -/// -/// [`shm_unlink(3)`]: https://man7.org/linux/man-pages/man3/shm_unlink.3.html -#[cfg(not(target_os = "android"))] -pub fn shm_unlink<P: ?Sized + NixPath>(name: &P) -> Result<()> { - let ret = - name.with_nix_path(|cstr| unsafe { libc::shm_unlink(cstr.as_ptr()) })?; - - Errno::result(ret).map(drop) -} diff --git a/vendor/nix/src/sys/mod.rs b/vendor/nix/src/sys/mod.rs deleted file mode 100644 index 2065059de..000000000 --- a/vendor/nix/src/sys/mod.rs +++ /dev/null @@ -1,228 +0,0 @@ -//! Mostly platform-specific functionality -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - all(target_os = "linux", not(target_env = "uclibc")), - target_os = "macos", - target_os = "netbsd" -))] -feature! { - #![feature = "aio"] - pub mod aio; -} - -feature! { - #![feature = "event"] - - #[cfg(any(target_os = "android", target_os = "linux"))] - #[allow(missing_docs)] - pub mod epoll; - - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[allow(missing_docs)] - pub mod event; - - #[cfg(any(target_os = "android", target_os = "linux"))] - #[allow(missing_docs)] - pub mod eventfd; -} - -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "redox", - target_os = "macos", - target_os = "netbsd", - target_os = "illumos", - target_os = "openbsd" -))] -#[cfg(feature = "ioctl")] -#[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))] -#[macro_use] -pub mod ioctl; - -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] -feature! { - #![feature = "fs"] - pub mod memfd; -} - -#[cfg(not(target_os = "redox"))] -feature! { - #![feature = "mman"] - pub mod mman; -} - -#[cfg(target_os = "linux")] -feature! { - #![feature = "personality"] - pub mod personality; -} - -feature! { - #![feature = "pthread"] - pub mod pthread; -} - -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" -))] -feature! { - #![feature = "ptrace"] - #[allow(missing_docs)] - pub mod ptrace; -} - -#[cfg(target_os = "linux")] -feature! { - #![feature = "quota"] - pub mod quota; -} - -#[cfg(target_os = "linux")] -feature! { - #![feature = "reboot"] - pub mod reboot; -} - -#[cfg(not(any( - target_os = "redox", - target_os = "fuchsia", - target_os = "illumos", - target_os = "haiku" -)))] -feature! { - #![feature = "resource"] - pub mod resource; -} - -#[cfg(not(target_os = "redox"))] -feature! { - #![feature = "poll"] - pub mod select; -} - -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos" -))] -feature! { - #![feature = "zerocopy"] - pub mod sendfile; -} - -pub mod signal; - -#[cfg(any(target_os = "android", target_os = "linux"))] -feature! { - #![feature = "signal"] - #[allow(missing_docs)] - pub mod signalfd; -} - -#[cfg(not(target_os = "redox"))] -feature! { - #![feature = "socket"] - #[allow(missing_docs)] - pub mod socket; -} - -feature! { - #![feature = "fs"] - #[allow(missing_docs)] - pub mod stat; -} - -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "openbsd" -))] -feature! { - #![feature = "fs"] - pub mod statfs; -} - -feature! { - #![feature = "fs"] - pub mod statvfs; -} - -#[cfg(any(target_os = "android", target_os = "linux"))] -#[cfg_attr(docsrs, doc(cfg(all())))] -#[allow(missing_docs)] -pub mod sysinfo; - -feature! { - #![feature = "term"] - #[allow(missing_docs)] - pub mod termios; -} - -#[allow(missing_docs)] -pub mod time; - -feature! { - #![feature = "uio"] - pub mod uio; -} - -feature! { - #![feature = "feature"] - pub mod utsname; -} - -feature! { - #![feature = "process"] - pub mod wait; -} - -#[cfg(any(target_os = "android", target_os = "linux"))] -feature! { - #![feature = "inotify"] - pub mod inotify; -} - -#[cfg(any(target_os = "android", target_os = "linux"))] -feature! { - #![feature = "time"] - pub mod timerfd; -} - -#[cfg(all( - any( - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd" - ), - feature = "time", - feature = "signal" -))] -feature! { - #![feature = "time"] - pub mod timer; -} diff --git a/vendor/nix/src/sys/personality.rs b/vendor/nix/src/sys/personality.rs deleted file mode 100644 index f295a05fa..000000000 --- a/vendor/nix/src/sys/personality.rs +++ /dev/null @@ -1,93 +0,0 @@ -//! Process execution domains -use crate::errno::Errno; -use crate::Result; - -use libc::{self, c_int, c_ulong}; - -libc_bitflags! { - /// Flags used and returned by [`get()`](fn.get.html) and - /// [`set()`](fn.set.html). - pub struct Persona: c_int { - /// Provide the legacy virtual address space layout. - ADDR_COMPAT_LAYOUT; - /// Disable address-space-layout randomization. - ADDR_NO_RANDOMIZE; - /// Limit the address space to 32 bits. - ADDR_LIMIT_32BIT; - /// Use `0xc0000000` as the offset at which to search a virtual memory - /// chunk on [`mmap(2)`], otherwise use `0xffffe000`. - /// - /// [`mmap(2)`]: https://man7.org/linux/man-pages/man2/mmap.2.html - ADDR_LIMIT_3GB; - /// User-space function pointers to signal handlers point to descriptors. - #[cfg(not(any(target_env = "musl", target_env = "uclibc")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - FDPIC_FUNCPTRS; - /// Map page 0 as read-only. - MMAP_PAGE_ZERO; - /// `PROT_READ` implies `PROT_EXEC` for [`mmap(2)`]. - /// - /// [`mmap(2)`]: https://man7.org/linux/man-pages/man2/mmap.2.html - READ_IMPLIES_EXEC; - /// No effects. - SHORT_INODE; - /// [`select(2)`], [`pselect(2)`], and [`ppoll(2)`] do not modify the - /// returned timeout argument when interrupted by a signal handler. - /// - /// [`select(2)`]: https://man7.org/linux/man-pages/man2/select.2.html - /// [`pselect(2)`]: https://man7.org/linux/man-pages/man2/pselect.2.html - /// [`ppoll(2)`]: https://man7.org/linux/man-pages/man2/ppoll.2.html - STICKY_TIMEOUTS; - /// Have [`uname(2)`] report a 2.6.40+ version number rather than a 3.x - /// version number. - /// - /// [`uname(2)`]: https://man7.org/linux/man-pages/man2/uname.2.html - #[cfg(not(any(target_env = "musl", target_env = "uclibc")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - UNAME26; - /// No effects. - WHOLE_SECONDS; - } -} - -/// Retrieve the current process personality. -/// -/// Returns a Result containing a Persona instance. -/// -/// Example: -/// -/// ``` -/// # use nix::sys::personality::{self, Persona}; -/// let pers = personality::get().unwrap(); -/// assert!(!pers.contains(Persona::WHOLE_SECONDS)); -/// ``` -pub fn get() -> Result<Persona> { - let res = unsafe { libc::personality(0xFFFFFFFF) }; - - Errno::result(res).map(Persona::from_bits_truncate) -} - -/// Set the current process personality. -/// -/// Returns a Result containing the *previous* personality for the -/// process, as a Persona. -/// -/// For more information, see [personality(2)](https://man7.org/linux/man-pages/man2/personality.2.html) -/// -/// **NOTE**: This call **replaces** the current personality entirely. -/// To **update** the personality, first call `get()` and then `set()` -/// with the modified persona. -/// -/// Example: -/// -/// ``` -/// # use nix::sys::personality::{self, Persona}; -/// let mut pers = personality::get().unwrap(); -/// assert!(!pers.contains(Persona::ADDR_NO_RANDOMIZE)); -/// personality::set(pers | Persona::ADDR_NO_RANDOMIZE).unwrap(); -/// ``` -pub fn set(persona: Persona) -> Result<Persona> { - let res = unsafe { libc::personality(persona.bits() as c_ulong) }; - - Errno::result(res).map(Persona::from_bits_truncate) -} diff --git a/vendor/nix/src/sys/pthread.rs b/vendor/nix/src/sys/pthread.rs deleted file mode 100644 index 6bad03a4d..000000000 --- a/vendor/nix/src/sys/pthread.rs +++ /dev/null @@ -1,43 +0,0 @@ -//! Low level threading primitives - -#[cfg(not(target_os = "redox"))] -use crate::errno::Errno; -#[cfg(not(target_os = "redox"))] -use crate::Result; -use libc::{self, pthread_t}; - -/// Identifies an individual thread. -pub type Pthread = pthread_t; - -/// Obtain ID of the calling thread (see -/// [`pthread_self(3)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_self.html) -/// -/// The thread ID returned by `pthread_self()` is not the same thing as -/// the kernel thread ID returned by a call to `gettid(2)`. -#[inline] -pub fn pthread_self() -> Pthread { - unsafe { libc::pthread_self() } -} - -feature! { -#![feature = "signal"] - -/// Send a signal to a thread (see [`pthread_kill(3)`]). -/// -/// If `signal` is `None`, `pthread_kill` will only preform error checking and -/// won't send any signal. -/// -/// [`pthread_kill(3)`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_kill.html -#[allow(clippy::not_unsafe_ptr_arg_deref)] -#[cfg(not(target_os = "redox"))] -pub fn pthread_kill<T>(thread: Pthread, signal: T) -> Result<()> - where T: Into<Option<crate::sys::signal::Signal>> -{ - let sig = match signal.into() { - Some(s) => s as libc::c_int, - None => 0, - }; - let res = unsafe { libc::pthread_kill(thread, sig) }; - Errno::result(res).map(drop) -} -} diff --git a/vendor/nix/src/sys/ptrace/bsd.rs b/vendor/nix/src/sys/ptrace/bsd.rs deleted file mode 100644 index ba267c657..000000000 --- a/vendor/nix/src/sys/ptrace/bsd.rs +++ /dev/null @@ -1,195 +0,0 @@ -use crate::errno::Errno; -use crate::sys::signal::Signal; -use crate::unistd::Pid; -use crate::Result; -use cfg_if::cfg_if; -use libc::{self, c_int}; -use std::ptr; - -pub type RequestType = c_int; - -cfg_if! { - if #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "openbsd"))] { - #[doc(hidden)] - pub type AddressType = *mut ::libc::c_char; - } else { - #[doc(hidden)] - pub type AddressType = *mut ::libc::c_void; - } -} - -libc_enum! { - #[repr(i32)] - /// Ptrace Request enum defining the action to be taken. - #[non_exhaustive] - pub enum Request { - PT_TRACE_ME, - PT_READ_I, - PT_READ_D, - #[cfg(target_os = "macos")] - #[cfg_attr(docsrs, doc(cfg(all())))] - PT_READ_U, - PT_WRITE_I, - PT_WRITE_D, - #[cfg(target_os = "macos")] - #[cfg_attr(docsrs, doc(cfg(all())))] - PT_WRITE_U, - PT_CONTINUE, - PT_KILL, - #[cfg(any(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos"), - all(target_os = "openbsd", target_arch = "x86_64"), - all(target_os = "netbsd", any(target_arch = "x86_64", - target_arch = "powerpc"))))] - PT_STEP, - PT_ATTACH, - PT_DETACH, - #[cfg(target_os = "macos")] - #[cfg_attr(docsrs, doc(cfg(all())))] - PT_SIGEXC, - #[cfg(target_os = "macos")] - #[cfg_attr(docsrs, doc(cfg(all())))] - PT_THUPDATE, - #[cfg(target_os = "macos")] - #[cfg_attr(docsrs, doc(cfg(all())))] - PT_ATTACHEXC - } -} - -unsafe fn ptrace_other( - request: Request, - pid: Pid, - addr: AddressType, - data: c_int, -) -> Result<c_int> { - Errno::result(libc::ptrace( - request as RequestType, - libc::pid_t::from(pid), - addr, - data, - )) - .map(|_| 0) -} - -/// Sets the process as traceable, as with `ptrace(PT_TRACEME, ...)` -/// -/// Indicates that this process is to be traced by its parent. -/// This is the only ptrace request to be issued by the tracee. -pub fn traceme() -> Result<()> { - unsafe { - ptrace_other(Request::PT_TRACE_ME, Pid::from_raw(0), ptr::null_mut(), 0) - .map(drop) - } -} - -/// Attach to a running process, as with `ptrace(PT_ATTACH, ...)` -/// -/// Attaches to the process specified by `pid`, making it a tracee of the calling process. -pub fn attach(pid: Pid) -> Result<()> { - unsafe { - ptrace_other(Request::PT_ATTACH, pid, ptr::null_mut(), 0).map(drop) - } -} - -/// Detaches the current running process, as with `ptrace(PT_DETACH, ...)` -/// -/// Detaches from the process specified by `pid` allowing it to run freely, optionally delivering a -/// signal specified by `sig`. -pub fn detach<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { - let data = match sig.into() { - Some(s) => s as c_int, - None => 0, - }; - unsafe { - ptrace_other(Request::PT_DETACH, pid, ptr::null_mut(), data).map(drop) - } -} - -/// Restart the stopped tracee process, as with `ptrace(PTRACE_CONT, ...)` -/// -/// Continues the execution of the process with PID `pid`, optionally -/// delivering a signal specified by `sig`. -pub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { - let data = match sig.into() { - Some(s) => s as c_int, - None => 0, - }; - unsafe { - // Ignore the useless return value - ptrace_other(Request::PT_CONTINUE, pid, 1 as AddressType, data) - .map(drop) - } -} - -/// Issues a kill request as with `ptrace(PT_KILL, ...)` -/// -/// This request is equivalent to `ptrace(PT_CONTINUE, ..., SIGKILL);` -pub fn kill(pid: Pid) -> Result<()> { - unsafe { - ptrace_other(Request::PT_KILL, pid, 0 as AddressType, 0).map(drop) - } -} - -/// Move the stopped tracee process forward by a single step as with -/// `ptrace(PT_STEP, ...)` -/// -/// Advances the execution of the process with PID `pid` by a single step optionally delivering a -/// signal specified by `sig`. -/// -/// # Example -/// ```rust -/// use nix::sys::ptrace::step; -/// use nix::unistd::Pid; -/// use nix::sys::signal::Signal; -/// use nix::sys::wait::*; -/// // If a process changes state to the stopped state because of a SIGUSR1 -/// // signal, this will step the process forward and forward the user -/// // signal to the stopped process -/// match waitpid(Pid::from_raw(-1), None) { -/// Ok(WaitStatus::Stopped(pid, Signal::SIGUSR1)) => { -/// let _ = step(pid, Signal::SIGUSR1); -/// } -/// _ => {}, -/// } -/// ``` -#[cfg(any( - any(target_os = "dragonfly", target_os = "freebsd", target_os = "macos"), - all(target_os = "openbsd", target_arch = "x86_64"), - all( - target_os = "netbsd", - any(target_arch = "x86_64", target_arch = "powerpc") - ) -))] -pub fn step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { - let data = match sig.into() { - Some(s) => s as c_int, - None => 0, - }; - unsafe { - ptrace_other(Request::PT_STEP, pid, ptr::null_mut(), data).map(drop) - } -} - -/// Reads a word from a processes memory at the given address -// Technically, ptrace doesn't dereference the pointer. It passes it directly -// to the kernel. -#[allow(clippy::not_unsafe_ptr_arg_deref)] -pub fn read(pid: Pid, addr: AddressType) -> Result<c_int> { - unsafe { - // Traditionally there was a difference between reading data or - // instruction memory but not in modern systems. - ptrace_other(Request::PT_READ_D, pid, addr, 0) - } -} - -/// Writes a word into the processes memory at the given address -// Technically, ptrace doesn't dereference the pointer. It passes it directly -// to the kernel. -#[allow(clippy::not_unsafe_ptr_arg_deref)] -pub fn write(pid: Pid, addr: AddressType, data: c_int) -> Result<()> { - unsafe { ptrace_other(Request::PT_WRITE_D, pid, addr, data).map(drop) } -} diff --git a/vendor/nix/src/sys/ptrace/linux.rs b/vendor/nix/src/sys/ptrace/linux.rs deleted file mode 100644 index 9687e05d4..000000000 --- a/vendor/nix/src/sys/ptrace/linux.rs +++ /dev/null @@ -1,558 +0,0 @@ -//! For detailed description of the ptrace requests, consult `man ptrace`. - -use crate::errno::Errno; -use crate::sys::signal::Signal; -use crate::unistd::Pid; -use crate::Result; -use cfg_if::cfg_if; -use libc::{self, c_long, c_void, siginfo_t}; -use std::{mem, ptr}; - -pub type AddressType = *mut ::libc::c_void; - -#[cfg(all( - target_os = "linux", - any( - all( - target_arch = "x86_64", - any(target_env = "gnu", target_env = "musl") - ), - all(target_arch = "x86", target_env = "gnu") - ) -))] -use libc::user_regs_struct; - -cfg_if! { - if #[cfg(any(all(target_os = "linux", target_arch = "s390x"), - all(target_os = "linux", target_env = "gnu"), - target_env = "uclibc"))] { - #[doc(hidden)] - pub type RequestType = ::libc::c_uint; - } else { - #[doc(hidden)] - pub type RequestType = ::libc::c_int; - } -} - -libc_enum! { - #[cfg_attr(not(any(target_env = "musl", target_env = "uclibc", target_os = "android")), repr(u32))] - #[cfg_attr(any(target_env = "musl", target_env = "uclibc", target_os = "android"), repr(i32))] - /// Ptrace Request enum defining the action to be taken. - #[non_exhaustive] - pub enum Request { - PTRACE_TRACEME, - PTRACE_PEEKTEXT, - PTRACE_PEEKDATA, - PTRACE_PEEKUSER, - PTRACE_POKETEXT, - PTRACE_POKEDATA, - PTRACE_POKEUSER, - PTRACE_CONT, - PTRACE_KILL, - PTRACE_SINGLESTEP, - #[cfg(any(all(target_os = "android", target_pointer_width = "32"), - all(target_os = "linux", any(target_env = "musl", - target_arch = "mips", - target_arch = "mips64", - target_arch = "x86_64", - target_pointer_width = "32"))))] - PTRACE_GETREGS, - #[cfg(any(all(target_os = "android", target_pointer_width = "32"), - all(target_os = "linux", any(target_env = "musl", - target_arch = "mips", - target_arch = "mips64", - target_arch = "x86_64", - target_pointer_width = "32"))))] - PTRACE_SETREGS, - #[cfg(any(all(target_os = "android", target_pointer_width = "32"), - all(target_os = "linux", any(target_env = "musl", - target_arch = "mips", - target_arch = "mips64", - target_arch = "x86_64", - target_pointer_width = "32"))))] - PTRACE_GETFPREGS, - #[cfg(any(all(target_os = "android", target_pointer_width = "32"), - all(target_os = "linux", any(target_env = "musl", - target_arch = "mips", - target_arch = "mips64", - target_arch = "x86_64", - target_pointer_width = "32"))))] - PTRACE_SETFPREGS, - PTRACE_ATTACH, - PTRACE_DETACH, - #[cfg(all(target_os = "linux", any(target_env = "musl", - target_arch = "mips", - target_arch = "mips64", - target_arch = "x86", - target_arch = "x86_64")))] - PTRACE_GETFPXREGS, - #[cfg(all(target_os = "linux", any(target_env = "musl", - target_arch = "mips", - target_arch = "mips64", - target_arch = "x86", - target_arch = "x86_64")))] - PTRACE_SETFPXREGS, - PTRACE_SYSCALL, - PTRACE_SETOPTIONS, - PTRACE_GETEVENTMSG, - PTRACE_GETSIGINFO, - PTRACE_SETSIGINFO, - #[cfg(all(target_os = "linux", not(any(target_arch = "mips", - target_arch = "mips64"))))] - PTRACE_GETREGSET, - #[cfg(all(target_os = "linux", not(any(target_arch = "mips", - target_arch = "mips64"))))] - PTRACE_SETREGSET, - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - PTRACE_SEIZE, - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - PTRACE_INTERRUPT, - #[cfg(all(target_os = "linux", not(any(target_arch = "mips", - target_arch = "mips64"))))] - PTRACE_LISTEN, - #[cfg(all(target_os = "linux", not(any(target_arch = "mips", - target_arch = "mips64"))))] - PTRACE_PEEKSIGINFO, - #[cfg(all(target_os = "linux", target_env = "gnu", - any(target_arch = "x86", target_arch = "x86_64")))] - PTRACE_SYSEMU, - #[cfg(all(target_os = "linux", target_env = "gnu", - any(target_arch = "x86", target_arch = "x86_64")))] - PTRACE_SYSEMU_SINGLESTEP, - } -} - -libc_enum! { - #[repr(i32)] - /// Using the ptrace options the tracer can configure the tracee to stop - /// at certain events. This enum is used to define those events as defined - /// in `man ptrace`. - #[non_exhaustive] - pub enum Event { - /// Event that stops before a return from fork or clone. - PTRACE_EVENT_FORK, - /// Event that stops before a return from vfork or clone. - PTRACE_EVENT_VFORK, - /// Event that stops before a return from clone. - PTRACE_EVENT_CLONE, - /// Event that stops before a return from execve. - PTRACE_EVENT_EXEC, - /// Event for a return from vfork. - PTRACE_EVENT_VFORK_DONE, - /// Event for a stop before an exit. Unlike the waitpid Exit status program. - /// registers can still be examined - PTRACE_EVENT_EXIT, - /// Stop triggered by a seccomp rule on a tracee. - PTRACE_EVENT_SECCOMP, - /// Stop triggered by the `INTERRUPT` syscall, or a group stop, - /// or when a new child is attached. - PTRACE_EVENT_STOP, - } -} - -libc_bitflags! { - /// Ptrace options used in conjunction with the PTRACE_SETOPTIONS request. - /// See `man ptrace` for more details. - pub struct Options: libc::c_int { - /// When delivering system call traps set a bit to allow tracer to - /// distinguish between normal stops or syscall stops. May not work on - /// all systems. - PTRACE_O_TRACESYSGOOD; - /// Stop tracee at next fork and start tracing the forked process. - PTRACE_O_TRACEFORK; - /// Stop tracee at next vfork call and trace the vforked process. - PTRACE_O_TRACEVFORK; - /// Stop tracee at next clone call and trace the cloned process. - PTRACE_O_TRACECLONE; - /// Stop tracee at next execve call. - PTRACE_O_TRACEEXEC; - /// Stop tracee at vfork completion. - PTRACE_O_TRACEVFORKDONE; - /// Stop tracee at next exit call. Stops before exit commences allowing - /// tracer to see location of exit and register states. - PTRACE_O_TRACEEXIT; - /// Stop tracee when a SECCOMP_RET_TRACE rule is triggered. See `man seccomp` for more - /// details. - PTRACE_O_TRACESECCOMP; - /// Send a SIGKILL to the tracee if the tracer exits. This is useful - /// for ptrace jailers to prevent tracees from escaping their control. - PTRACE_O_EXITKILL; - } -} - -fn ptrace_peek( - request: Request, - pid: Pid, - addr: AddressType, - data: *mut c_void, -) -> Result<c_long> { - let ret = unsafe { - Errno::clear(); - libc::ptrace(request as RequestType, libc::pid_t::from(pid), addr, data) - }; - match Errno::result(ret) { - Ok(..) | Err(Errno::UnknownErrno) => Ok(ret), - err @ Err(..) => err, - } -} - -/// Get user registers, as with `ptrace(PTRACE_GETREGS, ...)` -#[cfg(all( - target_os = "linux", - any( - all( - target_arch = "x86_64", - any(target_env = "gnu", target_env = "musl") - ), - all(target_arch = "x86", target_env = "gnu") - ) -))] -pub fn getregs(pid: Pid) -> Result<user_regs_struct> { - ptrace_get_data::<user_regs_struct>(Request::PTRACE_GETREGS, pid) -} - -/// Set user registers, as with `ptrace(PTRACE_SETREGS, ...)` -#[cfg(all( - target_os = "linux", - any( - all( - target_arch = "x86_64", - any(target_env = "gnu", target_env = "musl") - ), - all(target_arch = "x86", target_env = "gnu") - ) -))] -pub fn setregs(pid: Pid, regs: user_regs_struct) -> Result<()> { - let res = unsafe { - libc::ptrace( - Request::PTRACE_SETREGS as RequestType, - libc::pid_t::from(pid), - ptr::null_mut::<c_void>(), - ®s as *const _ as *const c_void, - ) - }; - Errno::result(res).map(drop) -} - -/// Function for ptrace requests that return values from the data field. -/// Some ptrace get requests populate structs or larger elements than `c_long` -/// and therefore use the data field to return values. This function handles these -/// requests. -fn ptrace_get_data<T>(request: Request, pid: Pid) -> Result<T> { - let mut data = mem::MaybeUninit::uninit(); - let res = unsafe { - libc::ptrace( - request as RequestType, - libc::pid_t::from(pid), - ptr::null_mut::<T>(), - data.as_mut_ptr() as *const _ as *const c_void, - ) - }; - Errno::result(res)?; - Ok(unsafe { data.assume_init() }) -} - -unsafe fn ptrace_other( - request: Request, - pid: Pid, - addr: AddressType, - data: *mut c_void, -) -> Result<c_long> { - Errno::result(libc::ptrace( - request as RequestType, - libc::pid_t::from(pid), - addr, - data, - )) - .map(|_| 0) -} - -/// Set options, as with `ptrace(PTRACE_SETOPTIONS,...)`. -pub fn setoptions(pid: Pid, options: Options) -> Result<()> { - let res = unsafe { - libc::ptrace( - Request::PTRACE_SETOPTIONS as RequestType, - libc::pid_t::from(pid), - ptr::null_mut::<c_void>(), - options.bits() as *mut c_void, - ) - }; - Errno::result(res).map(drop) -} - -/// Gets a ptrace event as described by `ptrace(PTRACE_GETEVENTMSG,...)` -pub fn getevent(pid: Pid) -> Result<c_long> { - ptrace_get_data::<c_long>(Request::PTRACE_GETEVENTMSG, pid) -} - -/// Get siginfo as with `ptrace(PTRACE_GETSIGINFO,...)` -pub fn getsiginfo(pid: Pid) -> Result<siginfo_t> { - ptrace_get_data::<siginfo_t>(Request::PTRACE_GETSIGINFO, pid) -} - -/// Set siginfo as with `ptrace(PTRACE_SETSIGINFO,...)` -pub fn setsiginfo(pid: Pid, sig: &siginfo_t) -> Result<()> { - let ret = unsafe { - Errno::clear(); - libc::ptrace( - Request::PTRACE_SETSIGINFO as RequestType, - libc::pid_t::from(pid), - ptr::null_mut::<c_void>(), - sig as *const _ as *const c_void, - ) - }; - match Errno::result(ret) { - Ok(_) => Ok(()), - Err(e) => Err(e), - } -} - -/// Sets the process as traceable, as with `ptrace(PTRACE_TRACEME, ...)` -/// -/// Indicates that this process is to be traced by its parent. -/// This is the only ptrace request to be issued by the tracee. -pub fn traceme() -> Result<()> { - unsafe { - ptrace_other( - Request::PTRACE_TRACEME, - Pid::from_raw(0), - ptr::null_mut(), - ptr::null_mut(), - ) - .map(drop) // ignore the useless return value - } -} - -/// Continue execution until the next syscall, as with `ptrace(PTRACE_SYSCALL, ...)` -/// -/// Arranges for the tracee to be stopped at the next entry to or exit from a system call, -/// optionally delivering a signal specified by `sig`. -pub fn syscall<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { - let data = match sig.into() { - Some(s) => s as i32 as *mut c_void, - None => ptr::null_mut(), - }; - unsafe { - ptrace_other(Request::PTRACE_SYSCALL, pid, ptr::null_mut(), data) - .map(drop) // ignore the useless return value - } -} - -/// Continue execution until the next syscall, as with `ptrace(PTRACE_SYSEMU, ...)` -/// -/// In contrast to the `syscall` function, the syscall stopped at will not be executed. -/// Thus the the tracee will only be stopped once per syscall, -/// optionally delivering a signal specified by `sig`. -#[cfg(all( - target_os = "linux", - target_env = "gnu", - any(target_arch = "x86", target_arch = "x86_64") -))] -pub fn sysemu<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { - let data = match sig.into() { - Some(s) => s as i32 as *mut c_void, - None => ptr::null_mut(), - }; - unsafe { - ptrace_other(Request::PTRACE_SYSEMU, pid, ptr::null_mut(), data) - .map(drop) - // ignore the useless return value - } -} - -/// Attach to a running process, as with `ptrace(PTRACE_ATTACH, ...)` -/// -/// Attaches to the process specified by `pid`, making it a tracee of the calling process. -pub fn attach(pid: Pid) -> Result<()> { - unsafe { - ptrace_other( - Request::PTRACE_ATTACH, - pid, - ptr::null_mut(), - ptr::null_mut(), - ) - .map(drop) // ignore the useless return value - } -} - -/// Attach to a running process, as with `ptrace(PTRACE_SEIZE, ...)` -/// -/// Attaches to the process specified in pid, making it a tracee of the calling process. -#[cfg(target_os = "linux")] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub fn seize(pid: Pid, options: Options) -> Result<()> { - unsafe { - ptrace_other( - Request::PTRACE_SEIZE, - pid, - ptr::null_mut(), - options.bits() as *mut c_void, - ) - .map(drop) // ignore the useless return value - } -} - -/// Detaches the current running process, as with `ptrace(PTRACE_DETACH, ...)` -/// -/// Detaches from the process specified by `pid` allowing it to run freely, optionally delivering a -/// signal specified by `sig`. -pub fn detach<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { - let data = match sig.into() { - Some(s) => s as i32 as *mut c_void, - None => ptr::null_mut(), - }; - unsafe { - ptrace_other(Request::PTRACE_DETACH, pid, ptr::null_mut(), data) - .map(drop) - } -} - -/// Restart the stopped tracee process, as with `ptrace(PTRACE_CONT, ...)` -/// -/// Continues the execution of the process with PID `pid`, optionally -/// delivering a signal specified by `sig`. -pub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { - let data = match sig.into() { - Some(s) => s as i32 as *mut c_void, - None => ptr::null_mut(), - }; - unsafe { - ptrace_other(Request::PTRACE_CONT, pid, ptr::null_mut(), data).map(drop) - // ignore the useless return value - } -} - -/// Stop a tracee, as with `ptrace(PTRACE_INTERRUPT, ...)` -/// -/// This request is equivalent to `ptrace(PTRACE_INTERRUPT, ...)` -#[cfg(target_os = "linux")] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub fn interrupt(pid: Pid) -> Result<()> { - unsafe { - ptrace_other( - Request::PTRACE_INTERRUPT, - pid, - ptr::null_mut(), - ptr::null_mut(), - ) - .map(drop) - } -} - -/// Issues a kill request as with `ptrace(PTRACE_KILL, ...)` -/// -/// This request is equivalent to `ptrace(PTRACE_CONT, ..., SIGKILL);` -pub fn kill(pid: Pid) -> Result<()> { - unsafe { - ptrace_other( - Request::PTRACE_KILL, - pid, - ptr::null_mut(), - ptr::null_mut(), - ) - .map(drop) - } -} - -/// Move the stopped tracee process forward by a single step as with -/// `ptrace(PTRACE_SINGLESTEP, ...)` -/// -/// Advances the execution of the process with PID `pid` by a single step optionally delivering a -/// signal specified by `sig`. -/// -/// # Example -/// ```rust -/// use nix::sys::ptrace::step; -/// use nix::unistd::Pid; -/// use nix::sys::signal::Signal; -/// use nix::sys::wait::*; -/// -/// // If a process changes state to the stopped state because of a SIGUSR1 -/// // signal, this will step the process forward and forward the user -/// // signal to the stopped process -/// match waitpid(Pid::from_raw(-1), None) { -/// Ok(WaitStatus::Stopped(pid, Signal::SIGUSR1)) => { -/// let _ = step(pid, Signal::SIGUSR1); -/// } -/// _ => {}, -/// } -/// ``` -pub fn step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { - let data = match sig.into() { - Some(s) => s as i32 as *mut c_void, - None => ptr::null_mut(), - }; - unsafe { - ptrace_other(Request::PTRACE_SINGLESTEP, pid, ptr::null_mut(), data) - .map(drop) - } -} - -/// Move the stopped tracee process forward by a single step or stop at the next syscall -/// as with `ptrace(PTRACE_SYSEMU_SINGLESTEP, ...)` -/// -/// Advances the execution by a single step or until the next syscall. -/// In case the tracee is stopped at a syscall, the syscall will not be executed. -/// Optionally, the signal specified by `sig` is delivered to the tracee upon continuation. -#[cfg(all( - target_os = "linux", - target_env = "gnu", - any(target_arch = "x86", target_arch = "x86_64") -))] -pub fn sysemu_step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { - let data = match sig.into() { - Some(s) => s as i32 as *mut c_void, - None => ptr::null_mut(), - }; - unsafe { - ptrace_other( - Request::PTRACE_SYSEMU_SINGLESTEP, - pid, - ptr::null_mut(), - data, - ) - .map(drop) // ignore the useless return value - } -} - -/// Reads a word from a processes memory at the given address -pub fn read(pid: Pid, addr: AddressType) -> Result<c_long> { - ptrace_peek(Request::PTRACE_PEEKDATA, pid, addr, ptr::null_mut()) -} - -/// Writes a word into the processes memory at the given address -/// -/// # Safety -/// -/// The `data` argument is passed directly to `ptrace(2)`. Read that man page -/// for guidance. -pub unsafe fn write( - pid: Pid, - addr: AddressType, - data: *mut c_void, -) -> Result<()> { - ptrace_other(Request::PTRACE_POKEDATA, pid, addr, data).map(drop) -} - -/// Reads a word from a user area at `offset`. -/// The user struct definition can be found in `/usr/include/sys/user.h`. -pub fn read_user(pid: Pid, offset: AddressType) -> Result<c_long> { - ptrace_peek(Request::PTRACE_PEEKUSER, pid, offset, ptr::null_mut()) -} - -/// Writes a word to a user area at `offset`. -/// The user struct definition can be found in `/usr/include/sys/user.h`. -/// -/// # Safety -/// -/// The `data` argument is passed directly to `ptrace(2)`. Read that man page -/// for guidance. -pub unsafe fn write_user( - pid: Pid, - offset: AddressType, - data: *mut c_void, -) -> Result<()> { - ptrace_other(Request::PTRACE_POKEUSER, pid, offset, data).map(drop) -} diff --git a/vendor/nix/src/sys/ptrace/mod.rs b/vendor/nix/src/sys/ptrace/mod.rs deleted file mode 100644 index 2b121c0b4..000000000 --- a/vendor/nix/src/sys/ptrace/mod.rs +++ /dev/null @@ -1,25 +0,0 @@ -///! Provides helpers for making ptrace system calls - -#[cfg(any(target_os = "android", target_os = "linux"))] -mod linux; - -#[cfg(any(target_os = "android", target_os = "linux"))] -pub use self::linux::*; - -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" -))] -mod bsd; - -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" -))] -pub use self::bsd::*; diff --git a/vendor/nix/src/sys/quota.rs b/vendor/nix/src/sys/quota.rs deleted file mode 100644 index b3c44ca70..000000000 --- a/vendor/nix/src/sys/quota.rs +++ /dev/null @@ -1,338 +0,0 @@ -//! Set and configure disk quotas for users, groups, or projects. -//! -//! # Examples -//! -//! Enabling and setting a quota: -//! -//! ```rust,no_run -//! # use nix::sys::quota::{Dqblk, quotactl_on, quotactl_set, QuotaFmt, QuotaType, QuotaValidFlags}; -//! quotactl_on(QuotaType::USRQUOTA, "/dev/sda1", QuotaFmt::QFMT_VFS_V1, "aquota.user").unwrap(); -//! let mut dqblk: Dqblk = Default::default(); -//! dqblk.set_blocks_hard_limit(10000); -//! dqblk.set_blocks_soft_limit(8000); -//! quotactl_set(QuotaType::USRQUOTA, "/dev/sda1", 50, &dqblk, QuotaValidFlags::QIF_BLIMITS).unwrap(); -//! ``` -use crate::errno::Errno; -use crate::{NixPath, Result}; -use libc::{self, c_char, c_int}; -use std::default::Default; -use std::{mem, ptr}; - -struct QuotaCmd(QuotaSubCmd, QuotaType); - -impl QuotaCmd { - #[allow(unused_unsafe)] - fn as_int(&self) -> c_int { - unsafe { libc::QCMD(self.0 as i32, self.1 as i32) } - } -} - -// linux quota version >= 2 -libc_enum! { - #[repr(i32)] - enum QuotaSubCmd { - Q_SYNC, - Q_QUOTAON, - Q_QUOTAOFF, - Q_GETQUOTA, - Q_SETQUOTA, - } -} - -libc_enum! { - /// The scope of the quota. - #[repr(i32)] - #[non_exhaustive] - pub enum QuotaType { - /// Specify a user quota - USRQUOTA, - /// Specify a group quota - GRPQUOTA, - } -} - -libc_enum! { - /// The type of quota format to use. - #[repr(i32)] - #[non_exhaustive] - pub enum QuotaFmt { - /// Use the original quota format. - QFMT_VFS_OLD, - /// Use the standard VFS v0 quota format. - /// - /// Handles 32-bit UIDs/GIDs and quota limits up to 2<sup>32</sup> bytes/2<sup>32</sup> inodes. - QFMT_VFS_V0, - /// Use the VFS v1 quota format. - /// - /// Handles 32-bit UIDs/GIDs and quota limits of 2<sup>64</sup> bytes/2<sup>64</sup> inodes. - QFMT_VFS_V1, - } -} - -libc_bitflags!( - /// Indicates the quota fields that are valid to read from. - #[derive(Default)] - pub struct QuotaValidFlags: u32 { - /// The block hard & soft limit fields. - QIF_BLIMITS; - /// The current space field. - QIF_SPACE; - /// The inode hard & soft limit fields. - QIF_ILIMITS; - /// The current inodes field. - QIF_INODES; - /// The disk use time limit field. - QIF_BTIME; - /// The file quote time limit field. - QIF_ITIME; - /// All block & inode limits. - QIF_LIMITS; - /// The space & inodes usage fields. - QIF_USAGE; - /// The time limit fields. - QIF_TIMES; - /// All fields. - QIF_ALL; - } -); - -/// Wrapper type for `if_dqblk` -#[repr(transparent)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct Dqblk(libc::dqblk); - -impl Default for Dqblk { - fn default() -> Dqblk { - Dqblk(libc::dqblk { - dqb_bhardlimit: 0, - dqb_bsoftlimit: 0, - dqb_curspace: 0, - dqb_ihardlimit: 0, - dqb_isoftlimit: 0, - dqb_curinodes: 0, - dqb_btime: 0, - dqb_itime: 0, - dqb_valid: 0, - }) - } -} - -impl Dqblk { - /// The absolute limit on disk quota blocks allocated. - pub fn blocks_hard_limit(&self) -> Option<u64> { - let valid_fields = - QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); - if valid_fields.contains(QuotaValidFlags::QIF_BLIMITS) { - Some(self.0.dqb_bhardlimit) - } else { - None - } - } - - /// Set the absolute limit on disk quota blocks allocated. - pub fn set_blocks_hard_limit(&mut self, limit: u64) { - self.0.dqb_bhardlimit = limit; - } - - /// Preferred limit on disk quota blocks - pub fn blocks_soft_limit(&self) -> Option<u64> { - let valid_fields = - QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); - if valid_fields.contains(QuotaValidFlags::QIF_BLIMITS) { - Some(self.0.dqb_bsoftlimit) - } else { - None - } - } - - /// Set the preferred limit on disk quota blocks allocated. - pub fn set_blocks_soft_limit(&mut self, limit: u64) { - self.0.dqb_bsoftlimit = limit; - } - - /// Current occupied space (bytes). - pub fn occupied_space(&self) -> Option<u64> { - let valid_fields = - QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); - if valid_fields.contains(QuotaValidFlags::QIF_SPACE) { - Some(self.0.dqb_curspace) - } else { - None - } - } - - /// Maximum number of allocated inodes. - pub fn inodes_hard_limit(&self) -> Option<u64> { - let valid_fields = - QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); - if valid_fields.contains(QuotaValidFlags::QIF_ILIMITS) { - Some(self.0.dqb_ihardlimit) - } else { - None - } - } - - /// Set the maximum number of allocated inodes. - pub fn set_inodes_hard_limit(&mut self, limit: u64) { - self.0.dqb_ihardlimit = limit; - } - - /// Preferred inode limit - pub fn inodes_soft_limit(&self) -> Option<u64> { - let valid_fields = - QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); - if valid_fields.contains(QuotaValidFlags::QIF_ILIMITS) { - Some(self.0.dqb_isoftlimit) - } else { - None - } - } - - /// Set the preferred limit of allocated inodes. - pub fn set_inodes_soft_limit(&mut self, limit: u64) { - self.0.dqb_isoftlimit = limit; - } - - /// Current number of allocated inodes. - pub fn allocated_inodes(&self) -> Option<u64> { - let valid_fields = - QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); - if valid_fields.contains(QuotaValidFlags::QIF_INODES) { - Some(self.0.dqb_curinodes) - } else { - None - } - } - - /// Time limit for excessive disk use. - pub fn block_time_limit(&self) -> Option<u64> { - let valid_fields = - QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); - if valid_fields.contains(QuotaValidFlags::QIF_BTIME) { - Some(self.0.dqb_btime) - } else { - None - } - } - - /// Set the time limit for excessive disk use. - pub fn set_block_time_limit(&mut self, limit: u64) { - self.0.dqb_btime = limit; - } - - /// Time limit for excessive files. - pub fn inode_time_limit(&self) -> Option<u64> { - let valid_fields = - QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); - if valid_fields.contains(QuotaValidFlags::QIF_ITIME) { - Some(self.0.dqb_itime) - } else { - None - } - } - - /// Set the time limit for excessive files. - pub fn set_inode_time_limit(&mut self, limit: u64) { - self.0.dqb_itime = limit; - } -} - -fn quotactl<P: ?Sized + NixPath>( - cmd: QuotaCmd, - special: Option<&P>, - id: c_int, - addr: *mut c_char, -) -> Result<()> { - unsafe { - Errno::clear(); - let res = match special { - Some(dev) => dev.with_nix_path(|path| { - libc::quotactl(cmd.as_int(), path.as_ptr(), id, addr) - }), - None => Ok(libc::quotactl(cmd.as_int(), ptr::null(), id, addr)), - }?; - - Errno::result(res).map(drop) - } -} - -/// Turn on disk quotas for a block device. -pub fn quotactl_on<P: ?Sized + NixPath>( - which: QuotaType, - special: &P, - format: QuotaFmt, - quota_file: &P, -) -> Result<()> { - quota_file.with_nix_path(|path| { - let mut path_copy = path.to_bytes_with_nul().to_owned(); - let p: *mut c_char = path_copy.as_mut_ptr() as *mut c_char; - quotactl( - QuotaCmd(QuotaSubCmd::Q_QUOTAON, which), - Some(special), - format as c_int, - p, - ) - })? -} - -/// Disable disk quotas for a block device. -pub fn quotactl_off<P: ?Sized + NixPath>( - which: QuotaType, - special: &P, -) -> Result<()> { - quotactl( - QuotaCmd(QuotaSubCmd::Q_QUOTAOFF, which), - Some(special), - 0, - ptr::null_mut(), - ) -} - -/// Update the on-disk copy of quota usages for a filesystem. -/// -/// If `special` is `None`, then all file systems with active quotas are sync'd. -pub fn quotactl_sync<P: ?Sized + NixPath>( - which: QuotaType, - special: Option<&P>, -) -> Result<()> { - quotactl( - QuotaCmd(QuotaSubCmd::Q_SYNC, which), - special, - 0, - ptr::null_mut(), - ) -} - -/// Get disk quota limits and current usage for the given user/group id. -pub fn quotactl_get<P: ?Sized + NixPath>( - which: QuotaType, - special: &P, - id: c_int, -) -> Result<Dqblk> { - let mut dqblk = mem::MaybeUninit::uninit(); - quotactl( - QuotaCmd(QuotaSubCmd::Q_GETQUOTA, which), - Some(special), - id, - dqblk.as_mut_ptr() as *mut c_char, - )?; - Ok(unsafe { Dqblk(dqblk.assume_init()) }) -} - -/// Configure quota values for the specified fields for a given user/group id. -pub fn quotactl_set<P: ?Sized + NixPath>( - which: QuotaType, - special: &P, - id: c_int, - dqblk: &Dqblk, - fields: QuotaValidFlags, -) -> Result<()> { - let mut dqblk_copy = *dqblk; - dqblk_copy.0.dqb_valid = fields.bits(); - quotactl( - QuotaCmd(QuotaSubCmd::Q_SETQUOTA, which), - Some(special), - id, - &mut dqblk_copy as *mut _ as *mut c_char, - ) -} diff --git a/vendor/nix/src/sys/reboot.rs b/vendor/nix/src/sys/reboot.rs deleted file mode 100644 index 02d98162b..000000000 --- a/vendor/nix/src/sys/reboot.rs +++ /dev/null @@ -1,48 +0,0 @@ -//! Reboot/shutdown or enable/disable Ctrl-Alt-Delete. - -use crate::errno::Errno; -use crate::Result; -use std::convert::Infallible; -use std::mem::drop; - -libc_enum! { - /// How exactly should the system be rebooted. - /// - /// See [`set_cad_enabled()`](fn.set_cad_enabled.html) for - /// enabling/disabling Ctrl-Alt-Delete. - #[repr(i32)] - #[non_exhaustive] - pub enum RebootMode { - /// Halt the system. - RB_HALT_SYSTEM, - /// Execute a kernel that has been loaded earlier with - /// [`kexec_load(2)`](https://man7.org/linux/man-pages/man2/kexec_load.2.html). - RB_KEXEC, - /// Stop the system and switch off power, if possible. - RB_POWER_OFF, - /// Restart the system. - RB_AUTOBOOT, - // we do not support Restart2. - /// Suspend the system using software suspend. - RB_SW_SUSPEND, - } -} - -/// Reboots or shuts down the system. -pub fn reboot(how: RebootMode) -> Result<Infallible> { - unsafe { libc::reboot(how as libc::c_int) }; - Err(Errno::last()) -} - -/// Enable or disable the reboot keystroke (Ctrl-Alt-Delete). -/// -/// Corresponds to calling `reboot(RB_ENABLE_CAD)` or `reboot(RB_DISABLE_CAD)` in C. -pub fn set_cad_enabled(enable: bool) -> Result<()> { - let cmd = if enable { - libc::RB_ENABLE_CAD - } else { - libc::RB_DISABLE_CAD - }; - let res = unsafe { libc::reboot(cmd) }; - Errno::result(res).map(drop) -} diff --git a/vendor/nix/src/sys/resource.rs b/vendor/nix/src/sys/resource.rs deleted file mode 100644 index 892773776..000000000 --- a/vendor/nix/src/sys/resource.rs +++ /dev/null @@ -1,443 +0,0 @@ -//! Configure the process resource limits. -use cfg_if::cfg_if; -use libc::{c_int, c_long, rusage}; - -use crate::errno::Errno; -use crate::sys::time::TimeVal; -use crate::Result; -pub use libc::rlim_t; -pub use libc::RLIM_INFINITY; -use std::mem; - -cfg_if! { - if #[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))]{ - use libc::{__rlimit_resource_t, rlimit}; - } else if #[cfg(any( - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "macos", - target_os = "ios", - target_os = "android", - target_os = "dragonfly", - all(target_os = "linux", not(target_env = "gnu")) - ))]{ - use libc::rlimit; - } -} - -libc_enum! { - /// Types of process resources. - /// - /// The Resource enum is platform dependent. Check different platform - /// manuals for more details. Some platform links have been provided for - /// easier reference (non-exhaustive). - /// - /// * [Linux](https://man7.org/linux/man-pages/man2/getrlimit.2.html) - /// * [FreeBSD](https://www.freebsd.org/cgi/man.cgi?query=setrlimit) - /// * [NetBSD](https://man.netbsd.org/setrlimit.2) - - // linux-gnu uses u_int as resource enum, which is implemented in libc as - // well. - // - // https://gcc.gnu.org/legacy-ml/gcc/2015-08/msg00441.html - // https://github.com/rust-lang/libc/blob/master/src/unix/linux_like/linux/gnu/mod.rs - #[cfg_attr(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")), repr(u32))] - #[cfg_attr(any( - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "macos", - target_os = "ios", - target_os = "android", - target_os = "dragonfly", - all(target_os = "linux", not(any(target_env = "gnu", target_env = "uclibc"))) - ), repr(i32))] - #[non_exhaustive] - pub enum Resource { - #[cfg(not(any(target_os = "freebsd", target_os = "netbsd", target_os = "openbsd")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The maximum amount (in bytes) of virtual memory the process is - /// allowed to map. - RLIMIT_AS, - /// The largest size (in bytes) core(5) file that may be created. - RLIMIT_CORE, - /// The maximum amount of cpu time (in seconds) to be used by each - /// process. - RLIMIT_CPU, - /// The maximum size (in bytes) of the data segment for a process - RLIMIT_DATA, - /// The largest size (in bytes) file that may be created. - RLIMIT_FSIZE, - /// The maximum number of open files for this process. - RLIMIT_NOFILE, - /// The maximum size (in bytes) of the stack segment for a process. - RLIMIT_STACK, - - #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The maximum number of kqueues this user id is allowed to create. - RLIMIT_KQUEUES, - - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// A limit on the combined number of flock locks and fcntl leases that - /// this process may establish. - RLIMIT_LOCKS, - - #[cfg(any( - target_os = "android", - target_os = "freebsd", - target_os = "openbsd", - target_os = "linux", - target_os = "netbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The maximum size (in bytes) which a process may lock into memory - /// using the mlock(2) system call. - RLIMIT_MEMLOCK, - - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// A limit on the number of bytes that can be allocated for POSIX - /// message queues for the real user ID of the calling process. - RLIMIT_MSGQUEUE, - - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// A ceiling to which the process's nice value can be raised using - /// setpriority or nice. - RLIMIT_NICE, - - #[cfg(any( - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd", - target_os = "linux", - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The maximum number of simultaneous processes for this user id. - RLIMIT_NPROC, - - #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The maximum number of pseudo-terminals this user id is allowed to - /// create. - RLIMIT_NPTS, - - #[cfg(any(target_os = "android", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd", - target_os = "linux", - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// When there is memory pressure and swap is available, prioritize - /// eviction of a process' resident pages beyond this amount (in bytes). - RLIMIT_RSS, - - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// A ceiling on the real-time priority that may be set for this process - /// using sched_setscheduler and sched_set‐ param. - RLIMIT_RTPRIO, - - #[cfg(any(target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// A limit (in microseconds) on the amount of CPU time that a process - /// scheduled under a real-time scheduling policy may con‐ sume without - /// making a blocking system call. - RLIMIT_RTTIME, - - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// A limit on the number of signals that may be queued for the real - /// user ID of the calling process. - RLIMIT_SIGPENDING, - - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The maximum size (in bytes) of socket buffer usage for this user. - RLIMIT_SBSIZE, - - #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The maximum size (in bytes) of the swap space that may be reserved - /// or used by all of this user id's processes. - RLIMIT_SWAP, - - #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// An alias for RLIMIT_AS. - RLIMIT_VMEM, - } -} - -/// Get the current processes resource limits -/// -/// The special value [`RLIM_INFINITY`] indicates that no limit will be -/// enforced. -/// -/// # Parameters -/// -/// * `resource`: The [`Resource`] that we want to get the limits of. -/// -/// # Examples -/// -/// ``` -/// # use nix::sys::resource::{getrlimit, Resource}; -/// -/// let (soft_limit, hard_limit) = getrlimit(Resource::RLIMIT_NOFILE).unwrap(); -/// println!("current soft_limit: {}", soft_limit); -/// println!("current hard_limit: {}", hard_limit); -/// ``` -/// -/// # References -/// -/// [getrlimit(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getrlimit.html#tag_16_215) -/// -/// [`Resource`]: enum.Resource.html -pub fn getrlimit(resource: Resource) -> Result<(rlim_t, rlim_t)> { - let mut old_rlim = mem::MaybeUninit::<rlimit>::uninit(); - - cfg_if! { - if #[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))]{ - let res = unsafe { libc::getrlimit(resource as __rlimit_resource_t, old_rlim.as_mut_ptr()) }; - } else { - let res = unsafe { libc::getrlimit(resource as c_int, old_rlim.as_mut_ptr()) }; - } - } - - Errno::result(res).map(|_| { - let rlimit { rlim_cur, rlim_max } = unsafe { old_rlim.assume_init() }; - (rlim_cur, rlim_max) - }) -} - -/// Set the current processes resource limits -/// -/// # Parameters -/// -/// * `resource`: The [`Resource`] that we want to set the limits of. -/// * `soft_limit`: The value that the kernel enforces for the corresponding -/// resource. -/// * `hard_limit`: The ceiling for the soft limit. Must be lower or equal to -/// the current hard limit for non-root users. -/// -/// The special value [`RLIM_INFINITY`] indicates that no limit will be -/// enforced. -/// -/// # Examples -/// -/// ``` -/// # use nix::sys::resource::{setrlimit, Resource}; -/// -/// let soft_limit = 512; -/// let hard_limit = 1024; -/// setrlimit(Resource::RLIMIT_NOFILE, soft_limit, hard_limit).unwrap(); -/// ``` -/// -/// # References -/// -/// [setrlimit(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getrlimit.html#tag_16_215) -/// -/// [`Resource`]: enum.Resource.html -/// -/// Note: `setrlimit` provides a safe wrapper to libc's `setrlimit`. -pub fn setrlimit( - resource: Resource, - soft_limit: rlim_t, - hard_limit: rlim_t, -) -> Result<()> { - let new_rlim = rlimit { - rlim_cur: soft_limit, - rlim_max: hard_limit, - }; - cfg_if! { - if #[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))]{ - let res = unsafe { libc::setrlimit(resource as __rlimit_resource_t, &new_rlim as *const rlimit) }; - }else{ - let res = unsafe { libc::setrlimit(resource as c_int, &new_rlim as *const rlimit) }; - } - } - - Errno::result(res).map(drop) -} - -libc_enum! { - /// Whose resource usage should be returned by [`getrusage`]. - #[repr(i32)] - #[non_exhaustive] - pub enum UsageWho { - /// Resource usage for the current process. - RUSAGE_SELF, - - /// Resource usage for all the children that have terminated and been waited for. - RUSAGE_CHILDREN, - - #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// Resource usage for the calling thread. - RUSAGE_THREAD, - } -} - -/// Output of `getrusage` with information about resource usage. Some of the fields -/// may be unused in some platforms, and will be always zeroed out. See their manuals -/// for details. -#[repr(transparent)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct Usage(rusage); - -impl AsRef<rusage> for Usage { - fn as_ref(&self) -> &rusage { - &self.0 - } -} - -impl AsMut<rusage> for Usage { - fn as_mut(&mut self) -> &mut rusage { - &mut self.0 - } -} - -impl Usage { - /// Total amount of time spent executing in user mode. - pub fn user_time(&self) -> TimeVal { - TimeVal::from(self.0.ru_utime) - } - - /// Total amount of time spent executing in kernel mode. - pub fn system_time(&self) -> TimeVal { - TimeVal::from(self.0.ru_stime) - } - - /// The resident set size at its peak, in kilobytes. - pub fn max_rss(&self) -> c_long { - self.0.ru_maxrss - } - - /// Integral value expressed in kilobytes times ticks of execution indicating - /// the amount of text memory shared with other processes. - pub fn shared_integral(&self) -> c_long { - self.0.ru_ixrss - } - - /// Integral value expressed in kilobytes times ticks of execution indicating - /// the amount of unshared memory used by data. - pub fn unshared_data_integral(&self) -> c_long { - self.0.ru_idrss - } - - /// Integral value expressed in kilobytes times ticks of execution indicating - /// the amount of unshared memory used for stack space. - pub fn unshared_stack_integral(&self) -> c_long { - self.0.ru_isrss - } - - /// Number of page faults that were served without resorting to I/O, with pages - /// that have been allocated previously by the kernel. - pub fn minor_page_faults(&self) -> c_long { - self.0.ru_minflt - } - - /// Number of page faults that were served through I/O (i.e. swap). - pub fn major_page_faults(&self) -> c_long { - self.0.ru_majflt - } - - /// Number of times all of the memory was fully swapped out. - pub fn full_swaps(&self) -> c_long { - self.0.ru_nswap - } - - /// Number of times a read was done from a block device. - pub fn block_reads(&self) -> c_long { - self.0.ru_inblock - } - - /// Number of times a write was done to a block device. - pub fn block_writes(&self) -> c_long { - self.0.ru_oublock - } - - /// Number of IPC messages sent. - pub fn ipc_sends(&self) -> c_long { - self.0.ru_msgsnd - } - - /// Number of IPC messages received. - pub fn ipc_receives(&self) -> c_long { - self.0.ru_msgrcv - } - - /// Number of signals received. - pub fn signals(&self) -> c_long { - self.0.ru_nsignals - } - - /// Number of times a context switch was voluntarily invoked. - pub fn voluntary_context_switches(&self) -> c_long { - self.0.ru_nvcsw - } - - /// Number of times a context switch was imposed by the kernel (usually due to - /// time slice expiring or preemption by a higher priority process). - pub fn involuntary_context_switches(&self) -> c_long { - self.0.ru_nivcsw - } -} - -/// Get usage information for a process, its children or the current thread -/// -/// Real time information can be obtained for either the current process or (in some -/// systems) thread, but information about children processes is only provided for -/// those that have terminated and been waited for (see [`super::wait::wait`]). -/// -/// Some information may be missing depending on the platform, and the way information -/// is provided for children may also vary. Check the manuals for details. -/// -/// # References -/// -/// * [getrusage(2)](https://pubs.opengroup.org/onlinepubs/009696699/functions/getrusage.html) -/// * [Linux](https://man7.org/linux/man-pages/man2/getrusage.2.html) -/// * [FreeBSD](https://www.freebsd.org/cgi/man.cgi?query=getrusage) -/// * [NetBSD](https://man.netbsd.org/getrusage.2) -/// * [MacOS](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getrusage.2.html) -/// -/// [`UsageWho`]: enum.UsageWho.html -/// -/// Note: `getrusage` provides a safe wrapper to libc's [`libc::getrusage`]. -pub fn getrusage(who: UsageWho) -> Result<Usage> { - unsafe { - let mut rusage = mem::MaybeUninit::<rusage>::uninit(); - let res = libc::getrusage(who as c_int, rusage.as_mut_ptr()); - Errno::result(res).map(|_| Usage(rusage.assume_init())) - } -} - -#[cfg(test)] -mod test { - use super::{getrusage, UsageWho}; - - #[test] - pub fn test_self_cpu_time() { - // Make sure some CPU time is used. - let mut numbers: Vec<i32> = (1..1_000_000).collect(); - numbers.iter_mut().for_each(|item| *item *= 2); - - // FIXME: this is here to help ensure the compiler does not optimize the whole - // thing away. Replace the assert with test::black_box once stabilized. - assert_eq!(numbers[100..200].iter().sum::<i32>(), 30_100); - - let usage = getrusage(UsageWho::RUSAGE_SELF) - .expect("Failed to call getrusage for SELF"); - let rusage = usage.as_ref(); - - let user = usage.user_time(); - assert!(user.tv_sec() > 0 || user.tv_usec() > 0); - assert_eq!(user.tv_sec(), rusage.ru_utime.tv_sec); - assert_eq!(user.tv_usec(), rusage.ru_utime.tv_usec); - } -} diff --git a/vendor/nix/src/sys/select.rs b/vendor/nix/src/sys/select.rs deleted file mode 100644 index 7a94cff87..000000000 --- a/vendor/nix/src/sys/select.rs +++ /dev/null @@ -1,455 +0,0 @@ -//! Portably monitor a group of file descriptors for readiness. -use crate::errno::Errno; -use crate::sys::time::{TimeSpec, TimeVal}; -use crate::Result; -use libc::{self, c_int}; -use std::convert::TryFrom; -use std::iter::FusedIterator; -use std::mem; -use std::ops::Range; -use std::os::unix::io::RawFd; -use std::ptr::{null, null_mut}; - -pub use libc::FD_SETSIZE; - -/// Contains a set of file descriptors used by [`select`] -#[repr(transparent)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct FdSet(libc::fd_set); - -fn assert_fd_valid(fd: RawFd) { - assert!( - usize::try_from(fd).map_or(false, |fd| fd < FD_SETSIZE), - "fd must be in the range 0..FD_SETSIZE", - ); -} - -impl FdSet { - /// Create an empty `FdSet` - pub fn new() -> FdSet { - let mut fdset = mem::MaybeUninit::uninit(); - unsafe { - libc::FD_ZERO(fdset.as_mut_ptr()); - FdSet(fdset.assume_init()) - } - } - - /// Add a file descriptor to an `FdSet` - pub fn insert(&mut self, fd: RawFd) { - assert_fd_valid(fd); - unsafe { libc::FD_SET(fd, &mut self.0) }; - } - - /// Remove a file descriptor from an `FdSet` - pub fn remove(&mut self, fd: RawFd) { - assert_fd_valid(fd); - unsafe { libc::FD_CLR(fd, &mut self.0) }; - } - - /// Test an `FdSet` for the presence of a certain file descriptor. - pub fn contains(&self, fd: RawFd) -> bool { - assert_fd_valid(fd); - unsafe { libc::FD_ISSET(fd, &self.0) } - } - - /// Remove all file descriptors from this `FdSet`. - pub fn clear(&mut self) { - unsafe { libc::FD_ZERO(&mut self.0) }; - } - - /// Finds the highest file descriptor in the set. - /// - /// Returns `None` if the set is empty. - /// - /// This can be used to calculate the `nfds` parameter of the [`select`] function. - /// - /// # Example - /// - /// ``` - /// # use nix::sys::select::FdSet; - /// let mut set = FdSet::new(); - /// set.insert(4); - /// set.insert(9); - /// assert_eq!(set.highest(), Some(9)); - /// ``` - /// - /// [`select`]: fn.select.html - pub fn highest(&self) -> Option<RawFd> { - self.fds(None).next_back() - } - - /// Returns an iterator over the file descriptors in the set. - /// - /// For performance, it takes an optional higher bound: the iterator will - /// not return any elements of the set greater than the given file - /// descriptor. - /// - /// # Examples - /// - /// ``` - /// # use nix::sys::select::FdSet; - /// # use std::os::unix::io::RawFd; - /// let mut set = FdSet::new(); - /// set.insert(4); - /// set.insert(9); - /// let fds: Vec<RawFd> = set.fds(None).collect(); - /// assert_eq!(fds, vec![4, 9]); - /// ``` - #[inline] - pub fn fds(&self, highest: Option<RawFd>) -> Fds { - Fds { - set: self, - range: 0..highest.map(|h| h as usize + 1).unwrap_or(FD_SETSIZE), - } - } -} - -impl Default for FdSet { - fn default() -> Self { - Self::new() - } -} - -/// Iterator over `FdSet`. -#[derive(Debug)] -pub struct Fds<'a> { - set: &'a FdSet, - range: Range<usize>, -} - -impl<'a> Iterator for Fds<'a> { - type Item = RawFd; - - fn next(&mut self) -> Option<RawFd> { - for i in &mut self.range { - if self.set.contains(i as RawFd) { - return Some(i as RawFd); - } - } - None - } - - #[inline] - fn size_hint(&self) -> (usize, Option<usize>) { - let (_, upper) = self.range.size_hint(); - (0, upper) - } -} - -impl<'a> DoubleEndedIterator for Fds<'a> { - #[inline] - fn next_back(&mut self) -> Option<RawFd> { - while let Some(i) = self.range.next_back() { - if self.set.contains(i as RawFd) { - return Some(i as RawFd); - } - } - None - } -} - -impl<'a> FusedIterator for Fds<'a> {} - -/// Monitors file descriptors for readiness -/// -/// Returns the total number of ready file descriptors in all sets. The sets are changed so that all -/// file descriptors that are ready for the given operation are set. -/// -/// When this function returns, `timeout` has an implementation-defined value. -/// -/// # Parameters -/// -/// * `nfds`: The highest file descriptor set in any of the passed `FdSet`s, plus 1. If `None`, this -/// is calculated automatically by calling [`FdSet::highest`] on all descriptor sets and adding 1 -/// to the maximum of that. -/// * `readfds`: File descriptors to check for being ready to read. -/// * `writefds`: File descriptors to check for being ready to write. -/// * `errorfds`: File descriptors to check for pending error conditions. -/// * `timeout`: Maximum time to wait for descriptors to become ready (`None` to block -/// indefinitely). -/// -/// # References -/// -/// [select(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/select.html) -/// -/// [`FdSet::highest`]: struct.FdSet.html#method.highest -pub fn select<'a, N, R, W, E, T>( - nfds: N, - readfds: R, - writefds: W, - errorfds: E, - timeout: T, -) -> Result<c_int> -where - N: Into<Option<c_int>>, - R: Into<Option<&'a mut FdSet>>, - W: Into<Option<&'a mut FdSet>>, - E: Into<Option<&'a mut FdSet>>, - T: Into<Option<&'a mut TimeVal>>, -{ - let mut readfds = readfds.into(); - let mut writefds = writefds.into(); - let mut errorfds = errorfds.into(); - let timeout = timeout.into(); - - let nfds = nfds.into().unwrap_or_else(|| { - readfds - .iter_mut() - .chain(writefds.iter_mut()) - .chain(errorfds.iter_mut()) - .map(|set| set.highest().unwrap_or(-1)) - .max() - .unwrap_or(-1) - + 1 - }); - - let readfds = readfds - .map(|set| set as *mut _ as *mut libc::fd_set) - .unwrap_or(null_mut()); - let writefds = writefds - .map(|set| set as *mut _ as *mut libc::fd_set) - .unwrap_or(null_mut()); - let errorfds = errorfds - .map(|set| set as *mut _ as *mut libc::fd_set) - .unwrap_or(null_mut()); - let timeout = timeout - .map(|tv| tv as *mut _ as *mut libc::timeval) - .unwrap_or(null_mut()); - - let res = - unsafe { libc::select(nfds, readfds, writefds, errorfds, timeout) }; - - Errno::result(res) -} - -feature! { -#![feature = "signal"] - -use crate::sys::signal::SigSet; - -/// Monitors file descriptors for readiness with an altered signal mask. -/// -/// Returns the total number of ready file descriptors in all sets. The sets are changed so that all -/// file descriptors that are ready for the given operation are set. -/// -/// When this function returns, the original signal mask is restored. -/// -/// Unlike [`select`](#fn.select), `pselect` does not mutate the `timeout` value. -/// -/// # Parameters -/// -/// * `nfds`: The highest file descriptor set in any of the passed `FdSet`s, plus 1. If `None`, this -/// is calculated automatically by calling [`FdSet::highest`] on all descriptor sets and adding 1 -/// to the maximum of that. -/// * `readfds`: File descriptors to check for read readiness -/// * `writefds`: File descriptors to check for write readiness -/// * `errorfds`: File descriptors to check for pending error conditions. -/// * `timeout`: Maximum time to wait for descriptors to become ready (`None` to block -/// indefinitely). -/// * `sigmask`: Signal mask to activate while waiting for file descriptors to turn -/// ready (`None` to set no alternative signal mask). -/// -/// # References -/// -/// [pselect(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pselect.html) -/// -/// [The new pselect() system call](https://lwn.net/Articles/176911/) -/// -/// [`FdSet::highest`]: struct.FdSet.html#method.highest -pub fn pselect<'a, N, R, W, E, T, S>(nfds: N, - readfds: R, - writefds: W, - errorfds: E, - timeout: T, - sigmask: S) -> Result<c_int> -where - N: Into<Option<c_int>>, - R: Into<Option<&'a mut FdSet>>, - W: Into<Option<&'a mut FdSet>>, - E: Into<Option<&'a mut FdSet>>, - T: Into<Option<&'a TimeSpec>>, - S: Into<Option<&'a SigSet>>, -{ - let mut readfds = readfds.into(); - let mut writefds = writefds.into(); - let mut errorfds = errorfds.into(); - let sigmask = sigmask.into(); - let timeout = timeout.into(); - - let nfds = nfds.into().unwrap_or_else(|| { - readfds.iter_mut() - .chain(writefds.iter_mut()) - .chain(errorfds.iter_mut()) - .map(|set| set.highest().unwrap_or(-1)) - .max() - .unwrap_or(-1) + 1 - }); - - let readfds = readfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut()); - let writefds = writefds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut()); - let errorfds = errorfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut()); - let timeout = timeout.map(|ts| ts.as_ref() as *const libc::timespec).unwrap_or(null()); - let sigmask = sigmask.map(|sm| sm.as_ref() as *const libc::sigset_t).unwrap_or(null()); - - let res = unsafe { - libc::pselect(nfds, readfds, writefds, errorfds, timeout, sigmask) - }; - - Errno::result(res) -} -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::sys::time::{TimeVal, TimeValLike}; - use crate::unistd::{pipe, write}; - use std::os::unix::io::RawFd; - - #[test] - fn fdset_insert() { - let mut fd_set = FdSet::new(); - - for i in 0..FD_SETSIZE { - assert!(!fd_set.contains(i as RawFd)); - } - - fd_set.insert(7); - - assert!(fd_set.contains(7)); - } - - #[test] - fn fdset_remove() { - let mut fd_set = FdSet::new(); - - for i in 0..FD_SETSIZE { - assert!(!fd_set.contains(i as RawFd)); - } - - fd_set.insert(7); - fd_set.remove(7); - - for i in 0..FD_SETSIZE { - assert!(!fd_set.contains(i as RawFd)); - } - } - - #[test] - fn fdset_clear() { - let mut fd_set = FdSet::new(); - fd_set.insert(1); - fd_set.insert((FD_SETSIZE / 2) as RawFd); - fd_set.insert((FD_SETSIZE - 1) as RawFd); - - fd_set.clear(); - - for i in 0..FD_SETSIZE { - assert!(!fd_set.contains(i as RawFd)); - } - } - - #[test] - fn fdset_highest() { - let mut set = FdSet::new(); - assert_eq!(set.highest(), None); - set.insert(0); - assert_eq!(set.highest(), Some(0)); - set.insert(90); - assert_eq!(set.highest(), Some(90)); - set.remove(0); - assert_eq!(set.highest(), Some(90)); - set.remove(90); - assert_eq!(set.highest(), None); - - set.insert(4); - set.insert(5); - set.insert(7); - assert_eq!(set.highest(), Some(7)); - } - - #[test] - fn fdset_fds() { - let mut set = FdSet::new(); - assert_eq!(set.fds(None).collect::<Vec<_>>(), vec![]); - set.insert(0); - assert_eq!(set.fds(None).collect::<Vec<_>>(), vec![0]); - set.insert(90); - assert_eq!(set.fds(None).collect::<Vec<_>>(), vec![0, 90]); - - // highest limit - assert_eq!(set.fds(Some(89)).collect::<Vec<_>>(), vec![0]); - assert_eq!(set.fds(Some(90)).collect::<Vec<_>>(), vec![0, 90]); - } - - #[test] - fn test_select() { - let (r1, w1) = pipe().unwrap(); - write(w1, b"hi!").unwrap(); - let (r2, _w2) = pipe().unwrap(); - - let mut fd_set = FdSet::new(); - fd_set.insert(r1); - fd_set.insert(r2); - - let mut timeout = TimeVal::seconds(10); - assert_eq!( - 1, - select(None, &mut fd_set, None, None, &mut timeout).unwrap() - ); - assert!(fd_set.contains(r1)); - assert!(!fd_set.contains(r2)); - } - - #[test] - fn test_select_nfds() { - let (r1, w1) = pipe().unwrap(); - write(w1, b"hi!").unwrap(); - let (r2, _w2) = pipe().unwrap(); - - let mut fd_set = FdSet::new(); - fd_set.insert(r1); - fd_set.insert(r2); - - let mut timeout = TimeVal::seconds(10); - assert_eq!( - 1, - select( - Some(fd_set.highest().unwrap() + 1), - &mut fd_set, - None, - None, - &mut timeout - ) - .unwrap() - ); - assert!(fd_set.contains(r1)); - assert!(!fd_set.contains(r2)); - } - - #[test] - fn test_select_nfds2() { - let (r1, w1) = pipe().unwrap(); - write(w1, b"hi!").unwrap(); - let (r2, _w2) = pipe().unwrap(); - - let mut fd_set = FdSet::new(); - fd_set.insert(r1); - fd_set.insert(r2); - - let mut timeout = TimeVal::seconds(10); - assert_eq!( - 1, - select( - ::std::cmp::max(r1, r2) + 1, - &mut fd_set, - None, - None, - &mut timeout - ) - .unwrap() - ); - assert!(fd_set.contains(r1)); - assert!(!fd_set.contains(r2)); - } -} diff --git a/vendor/nix/src/sys/sendfile.rs b/vendor/nix/src/sys/sendfile.rs deleted file mode 100644 index fb293a4e7..000000000 --- a/vendor/nix/src/sys/sendfile.rs +++ /dev/null @@ -1,277 +0,0 @@ -//! Send data from a file to a socket, bypassing userland. - -use cfg_if::cfg_if; -use std::os::unix::io::RawFd; -use std::ptr; - -use libc::{self, off_t}; - -use crate::errno::Errno; -use crate::Result; - -/// Copy up to `count` bytes to `out_fd` from `in_fd` starting at `offset`. -/// -/// Returns a `Result` with the number of bytes written. -/// -/// If `offset` is `None`, `sendfile` will begin reading at the current offset of `in_fd`and will -/// update the offset of `in_fd`. If `offset` is `Some`, `sendfile` will begin at the specified -/// offset and will not update the offset of `in_fd`. Instead, it will mutate `offset` to point to -/// the byte after the last byte copied. -/// -/// `in_fd` must support `mmap`-like operations and therefore cannot be a socket. -/// -/// For more information, see [the sendfile(2) man page.](https://man7.org/linux/man-pages/man2/sendfile.2.html) -#[cfg(any(target_os = "android", target_os = "linux"))] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub fn sendfile( - out_fd: RawFd, - in_fd: RawFd, - offset: Option<&mut off_t>, - count: usize, -) -> Result<usize> { - let offset = offset - .map(|offset| offset as *mut _) - .unwrap_or(ptr::null_mut()); - let ret = unsafe { libc::sendfile(out_fd, in_fd, offset, count) }; - Errno::result(ret).map(|r| r as usize) -} - -/// Copy up to `count` bytes to `out_fd` from `in_fd` starting at `offset`. -/// -/// Returns a `Result` with the number of bytes written. -/// -/// If `offset` is `None`, `sendfile` will begin reading at the current offset of `in_fd`and will -/// update the offset of `in_fd`. If `offset` is `Some`, `sendfile` will begin at the specified -/// offset and will not update the offset of `in_fd`. Instead, it will mutate `offset` to point to -/// the byte after the last byte copied. -/// -/// `in_fd` must support `mmap`-like operations and therefore cannot be a socket. -/// -/// For more information, see [the sendfile(2) man page.](https://man7.org/linux/man-pages/man2/sendfile.2.html) -#[cfg(target_os = "linux")] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub fn sendfile64( - out_fd: RawFd, - in_fd: RawFd, - offset: Option<&mut libc::off64_t>, - count: usize, -) -> Result<usize> { - let offset = offset - .map(|offset| offset as *mut _) - .unwrap_or(ptr::null_mut()); - let ret = unsafe { libc::sendfile64(out_fd, in_fd, offset, count) }; - Errno::result(ret).map(|r| r as usize) -} - -cfg_if! { - if #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos"))] { - use std::io::IoSlice; - - #[derive(Clone, Debug)] - struct SendfileHeaderTrailer<'a>( - libc::sf_hdtr, - Option<Vec<IoSlice<'a>>>, - Option<Vec<IoSlice<'a>>>, - ); - - impl<'a> SendfileHeaderTrailer<'a> { - fn new( - headers: Option<&'a [&'a [u8]]>, - trailers: Option<&'a [&'a [u8]]> - ) -> SendfileHeaderTrailer<'a> { - let header_iovecs: Option<Vec<IoSlice<'_>>> = - headers.map(|s| s.iter().map(|b| IoSlice::new(b)).collect()); - let trailer_iovecs: Option<Vec<IoSlice<'_>>> = - trailers.map(|s| s.iter().map(|b| IoSlice::new(b)).collect()); - SendfileHeaderTrailer( - libc::sf_hdtr { - headers: { - header_iovecs - .as_ref() - .map_or(ptr::null(), |v| v.as_ptr()) as *mut libc::iovec - }, - hdr_cnt: header_iovecs.as_ref().map(|v| v.len()).unwrap_or(0) as i32, - trailers: { - trailer_iovecs - .as_ref() - .map_or(ptr::null(), |v| v.as_ptr()) as *mut libc::iovec - }, - trl_cnt: trailer_iovecs.as_ref().map(|v| v.len()).unwrap_or(0) as i32 - }, - header_iovecs, - trailer_iovecs, - ) - } - } - } -} - -cfg_if! { - if #[cfg(target_os = "freebsd")] { - use libc::c_int; - - libc_bitflags!{ - /// Configuration options for [`sendfile`.](fn.sendfile.html) - pub struct SfFlags: c_int { - /// Causes `sendfile` to return EBUSY instead of blocking when attempting to read a - /// busy page. - SF_NODISKIO; - /// Causes `sendfile` to sleep until the network stack releases its reference to the - /// VM pages read. When `sendfile` returns, the data is not guaranteed to have been - /// sent, but it is safe to modify the file. - SF_SYNC; - /// Causes `sendfile` to cache exactly the number of pages specified in the - /// `readahead` parameter, disabling caching heuristics. - SF_USER_READAHEAD; - /// Causes `sendfile` not to cache the data read. - SF_NOCACHE; - } - } - - /// Read up to `count` bytes from `in_fd` starting at `offset` and write to `out_sock`. - /// - /// Returns a `Result` and a count of bytes written. Bytes written may be non-zero even if - /// an error occurs. - /// - /// `in_fd` must describe a regular file or shared memory object. `out_sock` must describe a - /// stream socket. - /// - /// If `offset` falls past the end of the file, the function returns success and zero bytes - /// written. - /// - /// If `count` is `None` or 0, bytes will be read from `in_fd` until reaching the end of - /// file (EOF). - /// - /// `headers` and `trailers` specify optional slices of byte slices to be sent before and - /// after the data read from `in_fd`, respectively. The length of headers and trailers sent - /// is included in the returned count of bytes written. The values of `offset` and `count` - /// do not apply to headers or trailers. - /// - /// `readahead` specifies the minimum number of pages to cache in memory ahead of the page - /// currently being sent. - /// - /// For more information, see - /// [the sendfile(2) man page.](https://www.freebsd.org/cgi/man.cgi?query=sendfile&sektion=2) - #[allow(clippy::too_many_arguments)] - pub fn sendfile( - in_fd: RawFd, - out_sock: RawFd, - offset: off_t, - count: Option<usize>, - headers: Option<&[&[u8]]>, - trailers: Option<&[&[u8]]>, - flags: SfFlags, - readahead: u16 - ) -> (Result<()>, off_t) { - // Readahead goes in upper 16 bits - // Flags goes in lower 16 bits - // see `man 2 sendfile` - let ra32 = u32::from(readahead); - let flags: u32 = (ra32 << 16) | (flags.bits() as u32); - let mut bytes_sent: off_t = 0; - let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers)); - let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr); - let return_code = unsafe { - libc::sendfile(in_fd, - out_sock, - offset, - count.unwrap_or(0), - hdtr_ptr as *mut libc::sf_hdtr, - &mut bytes_sent as *mut off_t, - flags as c_int) - }; - (Errno::result(return_code).and(Ok(())), bytes_sent) - } - } else if #[cfg(target_os = "dragonfly")] { - /// Read up to `count` bytes from `in_fd` starting at `offset` and write to `out_sock`. - /// - /// Returns a `Result` and a count of bytes written. Bytes written may be non-zero even if - /// an error occurs. - /// - /// `in_fd` must describe a regular file. `out_sock` must describe a stream socket. - /// - /// If `offset` falls past the end of the file, the function returns success and zero bytes - /// written. - /// - /// If `count` is `None` or 0, bytes will be read from `in_fd` until reaching the end of - /// file (EOF). - /// - /// `headers` and `trailers` specify optional slices of byte slices to be sent before and - /// after the data read from `in_fd`, respectively. The length of headers and trailers sent - /// is included in the returned count of bytes written. The values of `offset` and `count` - /// do not apply to headers or trailers. - /// - /// For more information, see - /// [the sendfile(2) man page.](https://leaf.dragonflybsd.org/cgi/web-man?command=sendfile§ion=2) - pub fn sendfile( - in_fd: RawFd, - out_sock: RawFd, - offset: off_t, - count: Option<usize>, - headers: Option<&[&[u8]]>, - trailers: Option<&[&[u8]]>, - ) -> (Result<()>, off_t) { - let mut bytes_sent: off_t = 0; - let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers)); - let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr); - let return_code = unsafe { - libc::sendfile(in_fd, - out_sock, - offset, - count.unwrap_or(0), - hdtr_ptr as *mut libc::sf_hdtr, - &mut bytes_sent as *mut off_t, - 0) - }; - (Errno::result(return_code).and(Ok(())), bytes_sent) - } - } else if #[cfg(any(target_os = "ios", target_os = "macos"))] { - /// Read bytes from `in_fd` starting at `offset` and write up to `count` bytes to - /// `out_sock`. - /// - /// Returns a `Result` and a count of bytes written. Bytes written may be non-zero even if - /// an error occurs. - /// - /// `in_fd` must describe a regular file. `out_sock` must describe a stream socket. - /// - /// If `offset` falls past the end of the file, the function returns success and zero bytes - /// written. - /// - /// If `count` is `None` or 0, bytes will be read from `in_fd` until reaching the end of - /// file (EOF). - /// - /// `hdtr` specifies an optional list of headers and trailers to be sent before and after - /// the data read from `in_fd`, respectively. The length of headers and trailers sent is - /// included in the returned count of bytes written. If any headers are specified and - /// `count` is non-zero, the length of the headers will be counted in the limit of total - /// bytes sent. Trailers do not count toward the limit of bytes sent and will always be sent - /// regardless. The value of `offset` does not affect headers or trailers. - /// - /// For more information, see - /// [the sendfile(2) man page.](https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man2/sendfile.2.html) - pub fn sendfile( - in_fd: RawFd, - out_sock: RawFd, - offset: off_t, - count: Option<off_t>, - headers: Option<&[&[u8]]>, - trailers: Option<&[&[u8]]> - ) -> (Result<()>, off_t) { - let mut len = count.unwrap_or(0); - let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers)); - let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr); - let return_code = unsafe { - libc::sendfile(in_fd, - out_sock, - offset, - &mut len as *mut off_t, - hdtr_ptr as *mut libc::sf_hdtr, - 0) - }; - (Errno::result(return_code).and(Ok(())), len) - } - } -} diff --git a/vendor/nix/src/sys/signal.rs b/vendor/nix/src/sys/signal.rs deleted file mode 100644 index d3746e609..000000000 --- a/vendor/nix/src/sys/signal.rs +++ /dev/null @@ -1,1348 +0,0 @@ -// Portions of this file are Copyright 2014 The Rust Project Developers. -// See https://www.rust-lang.org/policies/licenses. - -//! Operating system signals. - -use crate::errno::Errno; -use crate::{Error, Result}; -use cfg_if::cfg_if; -use std::fmt; -use std::mem; -#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] -use std::os::unix::io::RawFd; -use std::ptr; -use std::str::FromStr; - -#[cfg(not(any(target_os = "openbsd", target_os = "redox")))] -#[cfg(any(feature = "aio", feature = "signal"))] -pub use self::sigevent::*; - -#[cfg(any(feature = "aio", feature = "process", feature = "signal"))] -libc_enum! { - /// Types of operating system signals - // Currently there is only one definition of c_int in libc, as well as only one - // type for signal constants. - // We would prefer to use the libc::c_int alias in the repr attribute. Unfortunately - // this is not (yet) possible. - #[repr(i32)] - #[non_exhaustive] - #[cfg_attr(docsrs, doc(cfg(any(feature = "aio", feature = "signal"))))] - pub enum Signal { - /// Hangup - SIGHUP, - /// Interrupt - SIGINT, - /// Quit - SIGQUIT, - /// Illegal instruction (not reset when caught) - SIGILL, - /// Trace trap (not reset when caught) - SIGTRAP, - /// Abort - SIGABRT, - /// Bus error - SIGBUS, - /// Floating point exception - SIGFPE, - /// Kill (cannot be caught or ignored) - SIGKILL, - /// User defined signal 1 - SIGUSR1, - /// Segmentation violation - SIGSEGV, - /// User defined signal 2 - SIGUSR2, - /// Write on a pipe with no one to read it - SIGPIPE, - /// Alarm clock - SIGALRM, - /// Software termination signal from kill - SIGTERM, - /// Stack fault (obsolete) - #[cfg(all(any(target_os = "android", target_os = "emscripten", - target_os = "fuchsia", target_os = "linux"), - not(any(target_arch = "mips", target_arch = "mips64", - target_arch = "sparc64"))))] - SIGSTKFLT, - /// To parent on child stop or exit - SIGCHLD, - /// Continue a stopped process - SIGCONT, - /// Sendable stop signal not from tty - SIGSTOP, - /// Stop signal from tty - SIGTSTP, - /// To readers pgrp upon background tty read - SIGTTIN, - /// Like TTIN if (tp->t_local<OSTOP) - SIGTTOU, - /// Urgent condition on IO channel - SIGURG, - /// Exceeded CPU time limit - SIGXCPU, - /// Exceeded file size limit - SIGXFSZ, - /// Virtual time alarm - SIGVTALRM, - /// Profiling time alarm - SIGPROF, - /// Window size changes - SIGWINCH, - /// Input/output possible signal - #[cfg(not(target_os = "haiku"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - SIGIO, - #[cfg(any(target_os = "android", target_os = "emscripten", - target_os = "fuchsia", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// Power failure imminent. - SIGPWR, - /// Bad system call - SIGSYS, - #[cfg(not(any(target_os = "android", target_os = "emscripten", - target_os = "fuchsia", target_os = "linux", - target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// Emulator trap - SIGEMT, - #[cfg(not(any(target_os = "android", target_os = "emscripten", - target_os = "fuchsia", target_os = "linux", - target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// Information request - SIGINFO, - } - impl TryFrom<i32> -} - -#[cfg(feature = "signal")] -impl FromStr for Signal { - type Err = Error; - fn from_str(s: &str) -> Result<Signal> { - Ok(match s { - "SIGHUP" => Signal::SIGHUP, - "SIGINT" => Signal::SIGINT, - "SIGQUIT" => Signal::SIGQUIT, - "SIGILL" => Signal::SIGILL, - "SIGTRAP" => Signal::SIGTRAP, - "SIGABRT" => Signal::SIGABRT, - "SIGBUS" => Signal::SIGBUS, - "SIGFPE" => Signal::SIGFPE, - "SIGKILL" => Signal::SIGKILL, - "SIGUSR1" => Signal::SIGUSR1, - "SIGSEGV" => Signal::SIGSEGV, - "SIGUSR2" => Signal::SIGUSR2, - "SIGPIPE" => Signal::SIGPIPE, - "SIGALRM" => Signal::SIGALRM, - "SIGTERM" => Signal::SIGTERM, - #[cfg(all( - any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "linux" - ), - not(any( - target_arch = "mips", - target_arch = "mips64", - target_arch = "sparc64" - )) - ))] - "SIGSTKFLT" => Signal::SIGSTKFLT, - "SIGCHLD" => Signal::SIGCHLD, - "SIGCONT" => Signal::SIGCONT, - "SIGSTOP" => Signal::SIGSTOP, - "SIGTSTP" => Signal::SIGTSTP, - "SIGTTIN" => Signal::SIGTTIN, - "SIGTTOU" => Signal::SIGTTOU, - "SIGURG" => Signal::SIGURG, - "SIGXCPU" => Signal::SIGXCPU, - "SIGXFSZ" => Signal::SIGXFSZ, - "SIGVTALRM" => Signal::SIGVTALRM, - "SIGPROF" => Signal::SIGPROF, - "SIGWINCH" => Signal::SIGWINCH, - #[cfg(not(target_os = "haiku"))] - "SIGIO" => Signal::SIGIO, - #[cfg(any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "linux" - ))] - "SIGPWR" => Signal::SIGPWR, - "SIGSYS" => Signal::SIGSYS, - #[cfg(not(any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "linux", - target_os = "redox", - target_os = "haiku" - )))] - "SIGEMT" => Signal::SIGEMT, - #[cfg(not(any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "linux", - target_os = "redox", - target_os = "haiku" - )))] - "SIGINFO" => Signal::SIGINFO, - _ => return Err(Errno::EINVAL), - }) - } -} - -#[cfg(feature = "signal")] -impl Signal { - /// Returns name of signal. - /// - /// This function is equivalent to `<Signal as AsRef<str>>::as_ref()`, - /// with difference that returned string is `'static` - /// and not bound to `self`'s lifetime. - pub const fn as_str(self) -> &'static str { - match self { - Signal::SIGHUP => "SIGHUP", - Signal::SIGINT => "SIGINT", - Signal::SIGQUIT => "SIGQUIT", - Signal::SIGILL => "SIGILL", - Signal::SIGTRAP => "SIGTRAP", - Signal::SIGABRT => "SIGABRT", - Signal::SIGBUS => "SIGBUS", - Signal::SIGFPE => "SIGFPE", - Signal::SIGKILL => "SIGKILL", - Signal::SIGUSR1 => "SIGUSR1", - Signal::SIGSEGV => "SIGSEGV", - Signal::SIGUSR2 => "SIGUSR2", - Signal::SIGPIPE => "SIGPIPE", - Signal::SIGALRM => "SIGALRM", - Signal::SIGTERM => "SIGTERM", - #[cfg(all( - any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "linux" - ), - not(any( - target_arch = "mips", - target_arch = "mips64", - target_arch = "sparc64" - )) - ))] - Signal::SIGSTKFLT => "SIGSTKFLT", - Signal::SIGCHLD => "SIGCHLD", - Signal::SIGCONT => "SIGCONT", - Signal::SIGSTOP => "SIGSTOP", - Signal::SIGTSTP => "SIGTSTP", - Signal::SIGTTIN => "SIGTTIN", - Signal::SIGTTOU => "SIGTTOU", - Signal::SIGURG => "SIGURG", - Signal::SIGXCPU => "SIGXCPU", - Signal::SIGXFSZ => "SIGXFSZ", - Signal::SIGVTALRM => "SIGVTALRM", - Signal::SIGPROF => "SIGPROF", - Signal::SIGWINCH => "SIGWINCH", - #[cfg(not(target_os = "haiku"))] - Signal::SIGIO => "SIGIO", - #[cfg(any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "linux" - ))] - Signal::SIGPWR => "SIGPWR", - Signal::SIGSYS => "SIGSYS", - #[cfg(not(any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "linux", - target_os = "redox", - target_os = "haiku" - )))] - Signal::SIGEMT => "SIGEMT", - #[cfg(not(any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "linux", - target_os = "redox", - target_os = "haiku" - )))] - Signal::SIGINFO => "SIGINFO", - } - } -} - -#[cfg(feature = "signal")] -impl AsRef<str> for Signal { - fn as_ref(&self) -> &str { - self.as_str() - } -} - -#[cfg(feature = "signal")] -impl fmt::Display for Signal { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(self.as_ref()) - } -} - -#[cfg(feature = "signal")] -pub use self::Signal::*; - -#[cfg(target_os = "redox")] -#[cfg(feature = "signal")] -const SIGNALS: [Signal; 29] = [ - SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL, - SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT, - SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM, - SIGPROF, SIGWINCH, SIGIO, SIGSYS, -]; -#[cfg(target_os = "haiku")] -#[cfg(feature = "signal")] -const SIGNALS: [Signal; 28] = [ - SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL, - SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT, - SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM, - SIGPROF, SIGWINCH, SIGSYS, -]; -#[cfg(all( - any( - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia" - ), - not(any( - target_arch = "mips", - target_arch = "mips64", - target_arch = "sparc64" - )) -))] -#[cfg(feature = "signal")] -const SIGNALS: [Signal; 31] = [ - SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL, - SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGSTKFLT, SIGCHLD, - SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, - SIGVTALRM, SIGPROF, SIGWINCH, SIGIO, SIGPWR, SIGSYS, -]; -#[cfg(all( - any( - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia" - ), - any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64") -))] -#[cfg(feature = "signal")] -const SIGNALS: [Signal; 30] = [ - SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL, - SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT, - SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM, - SIGPROF, SIGWINCH, SIGIO, SIGPWR, SIGSYS, -]; -#[cfg(not(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia", - target_os = "emscripten", - target_os = "redox", - target_os = "haiku" -)))] -#[cfg(feature = "signal")] -const SIGNALS: [Signal; 31] = [ - SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL, - SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT, - SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM, - SIGPROF, SIGWINCH, SIGIO, SIGSYS, SIGEMT, SIGINFO, -]; - -feature! { -#![feature = "signal"] - -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -/// Iterate through all signals defined by this operating system -pub struct SignalIterator { - next: usize, -} - -impl Iterator for SignalIterator { - type Item = Signal; - - fn next(&mut self) -> Option<Signal> { - if self.next < SIGNALS.len() { - let next_signal = SIGNALS[self.next]; - self.next += 1; - Some(next_signal) - } else { - None - } - } -} - -impl Signal { - /// Iterate through all signals defined by this OS - pub const fn iterator() -> SignalIterator { - SignalIterator{next: 0} - } -} - -/// Alias for [`SIGABRT`] -pub const SIGIOT : Signal = SIGABRT; -/// Alias for [`SIGIO`] -#[cfg(not(target_os = "haiku"))] -pub const SIGPOLL : Signal = SIGIO; -/// Alias for [`SIGSYS`] -pub const SIGUNUSED : Signal = SIGSYS; - -cfg_if! { - if #[cfg(target_os = "redox")] { - type SaFlags_t = libc::c_ulong; - } else if #[cfg(target_env = "uclibc")] { - type SaFlags_t = libc::c_ulong; - } else { - type SaFlags_t = libc::c_int; - } -} -} - -#[cfg(feature = "signal")] -libc_bitflags! { - /// Controls the behavior of a [`SigAction`] - #[cfg_attr(docsrs, doc(cfg(feature = "signal")))] - pub struct SaFlags: SaFlags_t { - /// When catching a [`Signal::SIGCHLD`] signal, the signal will be - /// generated only when a child process exits, not when a child process - /// stops. - SA_NOCLDSTOP; - /// When catching a [`Signal::SIGCHLD`] signal, the system will not - /// create zombie processes when children of the calling process exit. - SA_NOCLDWAIT; - /// Further occurrences of the delivered signal are not masked during - /// the execution of the handler. - SA_NODEFER; - /// The system will deliver the signal to the process on a signal stack, - /// specified by each thread with sigaltstack(2). - SA_ONSTACK; - /// The handler is reset back to the default at the moment the signal is - /// delivered. - SA_RESETHAND; - /// Requests that certain system calls restart if interrupted by this - /// signal. See the man page for complete details. - SA_RESTART; - /// This flag is controlled internally by Nix. - SA_SIGINFO; - } -} - -#[cfg(feature = "signal")] -libc_enum! { - /// Specifies how certain functions should manipulate a signal mask - #[repr(i32)] - #[non_exhaustive] - #[cfg_attr(docsrs, doc(cfg(feature = "signal")))] - pub enum SigmaskHow { - /// The new mask is the union of the current mask and the specified set. - SIG_BLOCK, - /// The new mask is the intersection of the current mask and the - /// complement of the specified set. - SIG_UNBLOCK, - /// The current mask is replaced by the specified set. - SIG_SETMASK, - } -} - -feature! { -#![feature = "signal"] - -use crate::unistd::Pid; -use std::iter::Extend; -use std::iter::FromIterator; -use std::iter::IntoIterator; - -/// Specifies a set of [`Signal`]s that may be blocked, waited for, etc. -// We are using `transparent` here to be super sure that `SigSet` -// is represented exactly like the `sigset_t` struct from C. -#[repr(transparent)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct SigSet { - sigset: libc::sigset_t -} - -impl SigSet { - /// Initialize to include all signals. - #[doc(alias("sigfillset"))] - pub fn all() -> SigSet { - let mut sigset = mem::MaybeUninit::uninit(); - let _ = unsafe { libc::sigfillset(sigset.as_mut_ptr()) }; - - unsafe{ SigSet { sigset: sigset.assume_init() } } - } - - /// Initialize to include nothing. - #[doc(alias("sigemptyset"))] - pub fn empty() -> SigSet { - let mut sigset = mem::MaybeUninit::uninit(); - let _ = unsafe { libc::sigemptyset(sigset.as_mut_ptr()) }; - - unsafe{ SigSet { sigset: sigset.assume_init() } } - } - - /// Add the specified signal to the set. - #[doc(alias("sigaddset"))] - pub fn add(&mut self, signal: Signal) { - unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) }; - } - - /// Remove all signals from this set. - #[doc(alias("sigemptyset"))] - pub fn clear(&mut self) { - unsafe { libc::sigemptyset(&mut self.sigset as *mut libc::sigset_t) }; - } - - /// Remove the specified signal from this set. - #[doc(alias("sigdelset"))] - pub fn remove(&mut self, signal: Signal) { - unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) }; - } - - /// Return whether this set includes the specified signal. - #[doc(alias("sigismember"))] - pub fn contains(&self, signal: Signal) -> bool { - let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, signal as libc::c_int) }; - - match res { - 1 => true, - 0 => false, - _ => unreachable!("unexpected value from sigismember"), - } - } - - /// Returns an iterator that yields the signals contained in this set. - pub fn iter(&self) -> SigSetIter<'_> { - self.into_iter() - } - - /// Gets the currently blocked (masked) set of signals for the calling thread. - pub fn thread_get_mask() -> Result<SigSet> { - let mut oldmask = mem::MaybeUninit::uninit(); - do_pthread_sigmask(SigmaskHow::SIG_SETMASK, None, Some(oldmask.as_mut_ptr()))?; - Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}}) - } - - /// Sets the set of signals as the signal mask for the calling thread. - pub fn thread_set_mask(&self) -> Result<()> { - pthread_sigmask(SigmaskHow::SIG_SETMASK, Some(self), None) - } - - /// Adds the set of signals to the signal mask for the calling thread. - pub fn thread_block(&self) -> Result<()> { - pthread_sigmask(SigmaskHow::SIG_BLOCK, Some(self), None) - } - - /// Removes the set of signals from the signal mask for the calling thread. - pub fn thread_unblock(&self) -> Result<()> { - pthread_sigmask(SigmaskHow::SIG_UNBLOCK, Some(self), None) - } - - /// Sets the set of signals as the signal mask, and returns the old mask. - pub fn thread_swap_mask(&self, how: SigmaskHow) -> Result<SigSet> { - let mut oldmask = mem::MaybeUninit::uninit(); - do_pthread_sigmask(how, Some(self), Some(oldmask.as_mut_ptr()))?; - Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}}) - } - - /// Suspends execution of the calling thread until one of the signals in the - /// signal mask becomes pending, and returns the accepted signal. - #[cfg(not(target_os = "redox"))] // RedoxFS does not yet support sigwait - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn wait(&self) -> Result<Signal> { - use std::convert::TryFrom; - - let mut signum = mem::MaybeUninit::uninit(); - let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, signum.as_mut_ptr()) }; - - Errno::result(res).map(|_| unsafe { - Signal::try_from(signum.assume_init()).unwrap() - }) - } - - /// Converts a `libc::sigset_t` object to a [`SigSet`] without checking whether the - /// `libc::sigset_t` is already initialized. - /// - /// # Safety - /// - /// The `sigset` passed in must be a valid an initialized `libc::sigset_t` by calling either - /// [`sigemptyset(3)`](https://man7.org/linux/man-pages/man3/sigemptyset.3p.html) or - /// [`sigfillset(3)`](https://man7.org/linux/man-pages/man3/sigfillset.3p.html). - /// Otherwise, the results are undefined. - pub unsafe fn from_sigset_t_unchecked(sigset: libc::sigset_t) -> SigSet { - SigSet { sigset } - } -} - -impl AsRef<libc::sigset_t> for SigSet { - fn as_ref(&self) -> &libc::sigset_t { - &self.sigset - } -} - -// TODO: Consider specialization for the case where T is &SigSet and libc::sigorset is available. -impl Extend<Signal> for SigSet { - fn extend<T>(&mut self, iter: T) - where T: IntoIterator<Item = Signal> { - for signal in iter { - self.add(signal); - } - } -} - -impl FromIterator<Signal> for SigSet { - fn from_iter<T>(iter: T) -> Self - where T: IntoIterator<Item = Signal> { - let mut sigset = SigSet::empty(); - sigset.extend(iter); - sigset - } -} - -/// Iterator for a [`SigSet`]. -/// -/// Call [`SigSet::iter`] to create an iterator. -#[derive(Clone, Debug)] -pub struct SigSetIter<'a> { - sigset: &'a SigSet, - inner: SignalIterator, -} - -impl Iterator for SigSetIter<'_> { - type Item = Signal; - fn next(&mut self) -> Option<Signal> { - loop { - match self.inner.next() { - None => return None, - Some(signal) if self.sigset.contains(signal) => return Some(signal), - Some(_signal) => continue, - } - } - } -} - -impl<'a> IntoIterator for &'a SigSet { - type Item = Signal; - type IntoIter = SigSetIter<'a>; - fn into_iter(self) -> Self::IntoIter { - SigSetIter { sigset: self, inner: Signal::iterator() } - } -} - -/// A signal handler. -#[allow(unknown_lints)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum SigHandler { - /// Default signal handling. - SigDfl, - /// Request that the signal be ignored. - SigIgn, - /// Use the given signal-catching function, which takes in the signal. - Handler(extern fn(libc::c_int)), - /// Use the given signal-catching function, which takes in the signal, information about how - /// the signal was generated, and a pointer to the threads `ucontext_t`. - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - SigAction(extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void)) -} - -/// Action to take on receipt of a signal. Corresponds to `sigaction`. -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct SigAction { - sigaction: libc::sigaction -} - -impl SigAction { - /// Creates a new action. - /// - /// The `SA_SIGINFO` bit in the `flags` argument is ignored (it will be set only if `handler` - /// is the `SigAction` variant). `mask` specifies other signals to block during execution of - /// the signal-catching function. - pub fn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction { - unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) { - (*p).sa_sigaction = match handler { - SigHandler::SigDfl => libc::SIG_DFL, - SigHandler::SigIgn => libc::SIG_IGN, - SigHandler::Handler(f) => f as *const extern fn(libc::c_int) as usize, - #[cfg(not(target_os = "redox"))] - SigHandler::SigAction(f) => f as *const extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void) as usize, - }; - } - - let mut s = mem::MaybeUninit::<libc::sigaction>::uninit(); - unsafe { - let p = s.as_mut_ptr(); - install_sig(p, handler); - (*p).sa_flags = match handler { - #[cfg(not(target_os = "redox"))] - SigHandler::SigAction(_) => (flags | SaFlags::SA_SIGINFO).bits(), - _ => (flags - SaFlags::SA_SIGINFO).bits(), - }; - (*p).sa_mask = mask.sigset; - - SigAction { sigaction: s.assume_init() } - } - } - - /// Returns the flags set on the action. - pub fn flags(&self) -> SaFlags { - SaFlags::from_bits_truncate(self.sigaction.sa_flags) - } - - /// Returns the set of signals that are blocked during execution of the action's - /// signal-catching function. - pub fn mask(&self) -> SigSet { - SigSet { sigset: self.sigaction.sa_mask } - } - - /// Returns the action's handler. - pub fn handler(&self) -> SigHandler { - match self.sigaction.sa_sigaction { - libc::SIG_DFL => SigHandler::SigDfl, - libc::SIG_IGN => SigHandler::SigIgn, - #[cfg(not(target_os = "redox"))] - p if self.flags().contains(SaFlags::SA_SIGINFO) => - SigHandler::SigAction( - // Safe for one of two reasons: - // * The SigHandler was created by SigHandler::new, in which - // case the pointer is correct, or - // * The SigHandler was created by signal or sigaction, which - // are unsafe functions, so the caller should've somehow - // ensured that it is correctly initialized. - unsafe{ - *(&p as *const usize - as *const extern fn(_, _, _)) - } - as extern fn(_, _, _)), - p => SigHandler::Handler( - // Safe for one of two reasons: - // * The SigHandler was created by SigHandler::new, in which - // case the pointer is correct, or - // * The SigHandler was created by signal or sigaction, which - // are unsafe functions, so the caller should've somehow - // ensured that it is correctly initialized. - unsafe{ - *(&p as *const usize - as *const extern fn(libc::c_int)) - } - as extern fn(libc::c_int)), - } - } -} - -/// Changes the action taken by a process on receipt of a specific signal. -/// -/// `signal` can be any signal except `SIGKILL` or `SIGSTOP`. On success, it returns the previous -/// action for the given signal. If `sigaction` fails, no new signal handler is installed. -/// -/// # Safety -/// -/// * Signal handlers may be called at any point during execution, which limits -/// what is safe to do in the body of the signal-catching function. Be certain -/// to only make syscalls that are explicitly marked safe for signal handlers -/// and only share global data using atomics. -/// -/// * There is also no guarantee that the old signal handler was installed -/// correctly. If it was installed by this crate, it will be. But if it was -/// installed by, for example, C code, then there is no guarantee its function -/// pointer is valid. In that case, this function effectively dereferences a -/// raw pointer of unknown provenance. -pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigAction> { - let mut oldact = mem::MaybeUninit::<libc::sigaction>::uninit(); - - let res = libc::sigaction(signal as libc::c_int, - &sigaction.sigaction as *const libc::sigaction, - oldact.as_mut_ptr()); - - Errno::result(res).map(|_| SigAction { sigaction: oldact.assume_init() }) -} - -/// Signal management (see [signal(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html)) -/// -/// Installs `handler` for the given `signal`, returning the previous signal -/// handler. `signal` should only be used following another call to `signal` or -/// if the current handler is the default. The return value of `signal` is -/// undefined after setting the handler with [`sigaction`][SigActionFn]. -/// -/// # Safety -/// -/// If the pointer to the previous signal handler is invalid, undefined -/// behavior could be invoked when casting it back to a [`SigAction`][SigActionStruct]. -/// -/// # Examples -/// -/// Ignore `SIGINT`: -/// -/// ```no_run -/// # use nix::sys::signal::{self, Signal, SigHandler}; -/// unsafe { signal::signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap(); -/// ``` -/// -/// Use a signal handler to set a flag variable: -/// -/// ```no_run -/// # #[macro_use] extern crate lazy_static; -/// # use std::convert::TryFrom; -/// # use std::sync::atomic::{AtomicBool, Ordering}; -/// # use nix::sys::signal::{self, Signal, SigHandler}; -/// lazy_static! { -/// static ref SIGNALED: AtomicBool = AtomicBool::new(false); -/// } -/// -/// extern fn handle_sigint(signal: libc::c_int) { -/// let signal = Signal::try_from(signal).unwrap(); -/// SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed); -/// } -/// -/// fn main() { -/// let handler = SigHandler::Handler(handle_sigint); -/// unsafe { signal::signal(Signal::SIGINT, handler) }.unwrap(); -/// } -/// ``` -/// -/// # Errors -/// -/// Returns [`Error(Errno::EOPNOTSUPP)`] if `handler` is -/// [`SigAction`][SigActionStruct]. Use [`sigaction`][SigActionFn] instead. -/// -/// `signal` also returns any error from `libc::signal`, such as when an attempt -/// is made to catch a signal that cannot be caught or to ignore a signal that -/// cannot be ignored. -/// -/// [`Error::UnsupportedOperation`]: ../../enum.Error.html#variant.UnsupportedOperation -/// [SigActionStruct]: struct.SigAction.html -/// [sigactionFn]: fn.sigaction.html -pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result<SigHandler> { - let signal = signal as libc::c_int; - let res = match handler { - SigHandler::SigDfl => libc::signal(signal, libc::SIG_DFL), - SigHandler::SigIgn => libc::signal(signal, libc::SIG_IGN), - SigHandler::Handler(handler) => libc::signal(signal, handler as libc::sighandler_t), - #[cfg(not(target_os = "redox"))] - SigHandler::SigAction(_) => return Err(Errno::ENOTSUP), - }; - Errno::result(res).map(|oldhandler| { - match oldhandler { - libc::SIG_DFL => SigHandler::SigDfl, - libc::SIG_IGN => SigHandler::SigIgn, - p => SigHandler::Handler( - *(&p as *const usize - as *const extern fn(libc::c_int)) - as extern fn(libc::c_int)), - } - }) -} - -fn do_pthread_sigmask(how: SigmaskHow, - set: Option<&SigSet>, - oldset: Option<*mut libc::sigset_t>) -> Result<()> { - if set.is_none() && oldset.is_none() { - return Ok(()) - } - - let res = unsafe { - // if set or oldset is None, pass in null pointers instead - libc::pthread_sigmask(how as libc::c_int, - set.map_or_else(ptr::null::<libc::sigset_t>, - |s| &s.sigset as *const libc::sigset_t), - oldset.unwrap_or(ptr::null_mut()) - ) - }; - - Errno::result(res).map(drop) -} - -/// Manages the signal mask (set of blocked signals) for the calling thread. -/// -/// If the `set` parameter is `Some(..)`, then the signal mask will be updated with the signal set. -/// The `how` flag decides the type of update. If `set` is `None`, `how` will be ignored, -/// and no modification will take place. -/// -/// If the 'oldset' parameter is `Some(..)` then the current signal mask will be written into it. -/// -/// If both `set` and `oldset` is `Some(..)`, the current signal mask will be written into oldset, -/// and then it will be updated with `set`. -/// -/// If both `set` and `oldset` is None, this function is a no-op. -/// -/// For more information, visit the [`pthread_sigmask`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_sigmask.html), -/// or [`sigprocmask`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html) man pages. -pub fn pthread_sigmask(how: SigmaskHow, - set: Option<&SigSet>, - oldset: Option<&mut SigSet>) -> Result<()> -{ - do_pthread_sigmask(how, set, oldset.map(|os| &mut os.sigset as *mut _ )) -} - -/// Examine and change blocked signals. -/// -/// For more information see the [`sigprocmask` man -/// pages](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html). -pub fn sigprocmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut SigSet>) -> Result<()> { - if set.is_none() && oldset.is_none() { - return Ok(()) - } - - let res = unsafe { - // if set or oldset is None, pass in null pointers instead - libc::sigprocmask(how as libc::c_int, - set.map_or_else(ptr::null::<libc::sigset_t>, - |s| &s.sigset as *const libc::sigset_t), - oldset.map_or_else(ptr::null_mut::<libc::sigset_t>, - |os| &mut os.sigset as *mut libc::sigset_t)) - }; - - Errno::result(res).map(drop) -} - -/// Send a signal to a process -/// -/// # Arguments -/// -/// * `pid` - Specifies which processes should receive the signal. -/// - If positive, specifies an individual process. -/// - If zero, the signal will be sent to all processes whose group -/// ID is equal to the process group ID of the sender. This is a -#[cfg_attr(target_os = "fuchsia", doc = "variant of `killpg`.")] -#[cfg_attr(not(target_os = "fuchsia"), doc = "variant of [`killpg`].")] -/// - If `-1` and the process has super-user privileges, the signal -/// is sent to all processes exclusing system processes. -/// - If less than `-1`, the signal is sent to all processes whose -/// process group ID is equal to the absolute value of `pid`. -/// * `signal` - Signal to send. If `None`, error checking is performed -/// but no signal is actually sent. -/// -/// See Also -/// [`kill(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/kill.html) -pub fn kill<T: Into<Option<Signal>>>(pid: Pid, signal: T) -> Result<()> { - let res = unsafe { libc::kill(pid.into(), - match signal.into() { - Some(s) => s as libc::c_int, - None => 0, - }) }; - - Errno::result(res).map(drop) -} - -/// Send a signal to a process group -/// -/// # Arguments -/// -/// * `pgrp` - Process group to signal. If less then or equal 1, the behavior -/// is platform-specific. -/// * `signal` - Signal to send. If `None`, `killpg` will only preform error -/// checking and won't send any signal. -/// -/// See Also [killpg(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/killpg.html). -#[cfg(not(target_os = "fuchsia"))] -pub fn killpg<T: Into<Option<Signal>>>(pgrp: Pid, signal: T) -> Result<()> { - let res = unsafe { libc::killpg(pgrp.into(), - match signal.into() { - Some(s) => s as libc::c_int, - None => 0, - }) }; - - Errno::result(res).map(drop) -} - -/// Send a signal to the current thread -/// -/// See Also [raise(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/raise.html) -pub fn raise(signal: Signal) -> Result<()> { - let res = unsafe { libc::raise(signal as libc::c_int) }; - - Errno::result(res).map(drop) -} -} - -feature! { -#![any(feature = "aio", feature = "signal")] - -/// Identifies a thread for [`SigevNotify::SigevThreadId`] -#[cfg(target_os = "freebsd")] -pub type type_of_thread_id = libc::lwpid_t; -/// Identifies a thread for [`SigevNotify::SigevThreadId`] -#[cfg(target_os = "linux")] -pub type type_of_thread_id = libc::pid_t; - -/// Specifies the notification method used by a [`SigEvent`] -// sigval is actually a union of a int and a void*. But it's never really used -// as a pointer, because neither libc nor the kernel ever dereference it. nix -// therefore presents it as an intptr_t, which is how kevent uses it. -#[cfg(not(any(target_os = "openbsd", target_os = "redox")))] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum SigevNotify { - /// No notification will be delivered - SigevNone, - /// Notify by delivering a signal to the process. - SigevSignal { - /// Signal to deliver - signal: Signal, - /// Will be present in the `si_value` field of the [`libc::siginfo_t`] - /// structure of the queued signal. - si_value: libc::intptr_t - }, - // Note: SIGEV_THREAD is not implemented because libc::sigevent does not - // expose a way to set the union members needed by SIGEV_THREAD. - /// Notify by delivering an event to a kqueue. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - SigevKevent { - /// File descriptor of the kqueue to notify. - kq: RawFd, - /// Will be contained in the kevent's `udata` field. - udata: libc::intptr_t - }, - /// Notify by delivering a signal to a thread. - #[cfg(any(target_os = "freebsd", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - SigevThreadId { - /// Signal to send - signal: Signal, - /// LWP ID of the thread to notify - thread_id: type_of_thread_id, - /// Will be present in the `si_value` field of the [`libc::siginfo_t`] - /// structure of the queued signal. - si_value: libc::intptr_t - }, -} -} - -#[cfg(not(any(target_os = "openbsd", target_os = "redox")))] -#[cfg_attr(docsrs, doc(cfg(all())))] -mod sigevent { - feature! { - #![any(feature = "aio", feature = "signal")] - - use std::mem; - use std::ptr; - use super::SigevNotify; - #[cfg(any(target_os = "freebsd", target_os = "linux"))] - use super::type_of_thread_id; - - /// Used to request asynchronous notification of the completion of certain - /// events, such as POSIX AIO and timers. - #[repr(C)] - #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] - pub struct SigEvent { - sigevent: libc::sigevent - } - - impl SigEvent { - /// **Note:** this constructor does not allow the user to set the - /// `sigev_notify_kevent_flags` field. That's considered ok because on FreeBSD - /// at least those flags don't do anything useful. That field is part of a - /// union that shares space with the more genuinely useful fields. - /// - /// **Note:** This constructor also doesn't allow the caller to set the - /// `sigev_notify_function` or `sigev_notify_attributes` fields, which are - /// required for `SIGEV_THREAD`. That's considered ok because on no operating - /// system is `SIGEV_THREAD` the most efficient way to deliver AIO - /// notification. FreeBSD and DragonFly BSD programs should prefer `SIGEV_KEVENT`. - /// Linux, Solaris, and portable programs should prefer `SIGEV_THREAD_ID` or - /// `SIGEV_SIGNAL`. That field is part of a union that shares space with the - /// more genuinely useful `sigev_notify_thread_id` - // Allow invalid_value warning on Fuchsia only. - // See https://github.com/nix-rust/nix/issues/1441 - #[cfg_attr(target_os = "fuchsia", allow(invalid_value))] - pub fn new(sigev_notify: SigevNotify) -> SigEvent { - let mut sev = unsafe { mem::MaybeUninit::<libc::sigevent>::zeroed().assume_init() }; - sev.sigev_notify = match sigev_notify { - SigevNotify::SigevNone => libc::SIGEV_NONE, - SigevNotify::SigevSignal{..} => libc::SIGEV_SIGNAL, - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - SigevNotify::SigevKevent{..} => libc::SIGEV_KEVENT, - #[cfg(target_os = "freebsd")] - SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID, - #[cfg(all(target_os = "linux", target_env = "gnu", not(target_arch = "mips")))] - SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID, - #[cfg(all(target_os = "linux", target_env = "uclibc"))] - SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID, - #[cfg(any(all(target_os = "linux", target_env = "musl"), target_arch = "mips"))] - SigevNotify::SigevThreadId{..} => 4 // No SIGEV_THREAD_ID defined - }; - sev.sigev_signo = match sigev_notify { - SigevNotify::SigevSignal{ signal, .. } => signal as libc::c_int, - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - SigevNotify::SigevKevent{ kq, ..} => kq, - #[cfg(any(target_os = "linux", target_os = "freebsd"))] - SigevNotify::SigevThreadId{ signal, .. } => signal as libc::c_int, - _ => 0 - }; - sev.sigev_value.sival_ptr = match sigev_notify { - SigevNotify::SigevNone => ptr::null_mut::<libc::c_void>(), - SigevNotify::SigevSignal{ si_value, .. } => si_value as *mut libc::c_void, - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - SigevNotify::SigevKevent{ udata, .. } => udata as *mut libc::c_void, - #[cfg(any(target_os = "freebsd", target_os = "linux"))] - SigevNotify::SigevThreadId{ si_value, .. } => si_value as *mut libc::c_void, - }; - SigEvent::set_tid(&mut sev, &sigev_notify); - SigEvent{sigevent: sev} - } - - #[cfg(any(target_os = "freebsd", target_os = "linux"))] - fn set_tid(sev: &mut libc::sigevent, sigev_notify: &SigevNotify) { - sev.sigev_notify_thread_id = match *sigev_notify { - SigevNotify::SigevThreadId { thread_id, .. } => thread_id, - _ => 0 as type_of_thread_id - }; - } - - #[cfg(not(any(target_os = "freebsd", target_os = "linux")))] - fn set_tid(_sev: &mut libc::sigevent, _sigev_notify: &SigevNotify) { - } - - /// Return a copy of the inner structure - pub fn sigevent(&self) -> libc::sigevent { - self.sigevent - } - - /// Returns a mutable pointer to the `sigevent` wrapped by `self` - pub fn as_mut_ptr(&mut self) -> *mut libc::sigevent { - &mut self.sigevent - } - } - - impl<'a> From<&'a libc::sigevent> for SigEvent { - fn from(sigevent: &libc::sigevent) -> Self { - SigEvent{ sigevent: *sigevent } - } - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - #[cfg(not(target_os = "redox"))] - use std::thread; - - #[test] - fn test_contains() { - let mut mask = SigSet::empty(); - mask.add(SIGUSR1); - - assert!(mask.contains(SIGUSR1)); - assert!(!mask.contains(SIGUSR2)); - - let all = SigSet::all(); - assert!(all.contains(SIGUSR1)); - assert!(all.contains(SIGUSR2)); - } - - #[test] - fn test_clear() { - let mut set = SigSet::all(); - set.clear(); - for signal in Signal::iterator() { - assert!(!set.contains(signal)); - } - } - - #[test] - fn test_from_str_round_trips() { - for signal in Signal::iterator() { - assert_eq!(signal.as_ref().parse::<Signal>().unwrap(), signal); - assert_eq!(signal.to_string().parse::<Signal>().unwrap(), signal); - } - } - - #[test] - fn test_from_str_invalid_value() { - let errval = Err(Errno::EINVAL); - assert_eq!("NOSIGNAL".parse::<Signal>(), errval); - assert_eq!("kill".parse::<Signal>(), errval); - assert_eq!("9".parse::<Signal>(), errval); - } - - #[test] - fn test_extend() { - let mut one_signal = SigSet::empty(); - one_signal.add(SIGUSR1); - - let mut two_signals = SigSet::empty(); - two_signals.add(SIGUSR2); - two_signals.extend(&one_signal); - - assert!(two_signals.contains(SIGUSR1)); - assert!(two_signals.contains(SIGUSR2)); - } - - #[test] - #[cfg(not(target_os = "redox"))] - fn test_thread_signal_set_mask() { - thread::spawn(|| { - let prev_mask = SigSet::thread_get_mask() - .expect("Failed to get existing signal mask!"); - - let mut test_mask = prev_mask; - test_mask.add(SIGUSR1); - - test_mask.thread_set_mask().expect("assertion failed"); - let new_mask = - SigSet::thread_get_mask().expect("Failed to get new mask!"); - - assert!(new_mask.contains(SIGUSR1)); - assert!(!new_mask.contains(SIGUSR2)); - - prev_mask - .thread_set_mask() - .expect("Failed to revert signal mask!"); - }) - .join() - .unwrap(); - } - - #[test] - #[cfg(not(target_os = "redox"))] - fn test_thread_signal_block() { - thread::spawn(|| { - let mut mask = SigSet::empty(); - mask.add(SIGUSR1); - - mask.thread_block().expect("assertion failed"); - - assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1)); - }) - .join() - .unwrap(); - } - - #[test] - #[cfg(not(target_os = "redox"))] - fn test_thread_signal_unblock() { - thread::spawn(|| { - let mut mask = SigSet::empty(); - mask.add(SIGUSR1); - - mask.thread_unblock().expect("assertion failed"); - - assert!(!SigSet::thread_get_mask().unwrap().contains(SIGUSR1)); - }) - .join() - .unwrap(); - } - - #[test] - #[cfg(not(target_os = "redox"))] - fn test_thread_signal_swap() { - thread::spawn(|| { - let mut mask = SigSet::empty(); - mask.add(SIGUSR1); - mask.thread_block().unwrap(); - - assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1)); - - let mut mask2 = SigSet::empty(); - mask2.add(SIGUSR2); - - let oldmask = - mask2.thread_swap_mask(SigmaskHow::SIG_SETMASK).unwrap(); - - assert!(oldmask.contains(SIGUSR1)); - assert!(!oldmask.contains(SIGUSR2)); - - assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR2)); - }) - .join() - .unwrap(); - } - - #[test] - fn test_from_and_into_iterator() { - let sigset = SigSet::from_iter(vec![Signal::SIGUSR1, Signal::SIGUSR2]); - let signals = sigset.into_iter().collect::<Vec<Signal>>(); - assert_eq!(signals, [Signal::SIGUSR1, Signal::SIGUSR2]); - } - - #[test] - #[cfg(not(target_os = "redox"))] - fn test_sigaction() { - thread::spawn(|| { - extern "C" fn test_sigaction_handler(_: libc::c_int) {} - extern "C" fn test_sigaction_action( - _: libc::c_int, - _: *mut libc::siginfo_t, - _: *mut libc::c_void, - ) { - } - - let handler_sig = SigHandler::Handler(test_sigaction_handler); - - let flags = - SaFlags::SA_ONSTACK | SaFlags::SA_RESTART | SaFlags::SA_SIGINFO; - - let mut mask = SigSet::empty(); - mask.add(SIGUSR1); - - let action_sig = SigAction::new(handler_sig, flags, mask); - - assert_eq!( - action_sig.flags(), - SaFlags::SA_ONSTACK | SaFlags::SA_RESTART - ); - assert_eq!(action_sig.handler(), handler_sig); - - mask = action_sig.mask(); - assert!(mask.contains(SIGUSR1)); - assert!(!mask.contains(SIGUSR2)); - - let handler_act = SigHandler::SigAction(test_sigaction_action); - let action_act = SigAction::new(handler_act, flags, mask); - assert_eq!(action_act.handler(), handler_act); - - let action_dfl = SigAction::new(SigHandler::SigDfl, flags, mask); - assert_eq!(action_dfl.handler(), SigHandler::SigDfl); - - let action_ign = SigAction::new(SigHandler::SigIgn, flags, mask); - assert_eq!(action_ign.handler(), SigHandler::SigIgn); - }) - .join() - .unwrap(); - } - - #[test] - #[cfg(not(target_os = "redox"))] - fn test_sigwait() { - thread::spawn(|| { - let mut mask = SigSet::empty(); - mask.add(SIGUSR1); - mask.add(SIGUSR2); - mask.thread_block().unwrap(); - - raise(SIGUSR1).unwrap(); - assert_eq!(mask.wait().unwrap(), SIGUSR1); - }) - .join() - .unwrap(); - } - - #[test] - fn test_from_sigset_t_unchecked() { - let src_set = SigSet::empty(); - let set = unsafe { SigSet::from_sigset_t_unchecked(src_set.sigset) }; - - for signal in Signal::iterator() { - assert!(!set.contains(signal)); - } - - let src_set = SigSet::all(); - let set = unsafe { SigSet::from_sigset_t_unchecked(src_set.sigset) }; - - for signal in Signal::iterator() { - assert!(set.contains(signal)); - } - } -} diff --git a/vendor/nix/src/sys/signalfd.rs b/vendor/nix/src/sys/signalfd.rs deleted file mode 100644 index 095e59085..000000000 --- a/vendor/nix/src/sys/signalfd.rs +++ /dev/null @@ -1,175 +0,0 @@ -//! Interface for the `signalfd` syscall. -//! -//! # Signal discarding -//! When a signal can't be delivered to a process (or thread), it will become a pending signal. -//! Failure to deliver could happen if the signal is blocked by every thread in the process or if -//! the signal handler is still handling a previous signal. -//! -//! If a signal is sent to a process (or thread) that already has a pending signal of the same -//! type, it will be discarded. This means that if signals of the same type are received faster than -//! they are processed, some of those signals will be dropped. Because of this limitation, -//! `signalfd` in itself cannot be used for reliable communication between processes or threads. -//! -//! Once the signal is unblocked, or the signal handler is finished, and a signal is still pending -//! (ie. not consumed from a signalfd) it will be delivered to the signal handler. -//! -//! Please note that signal discarding is not specific to `signalfd`, but also happens with regular -//! signal handlers. -use crate::errno::Errno; -pub use crate::sys::signal::{self, SigSet}; -use crate::unistd; -use crate::Result; -pub use libc::signalfd_siginfo as siginfo; - -use std::mem; -use std::os::unix::io::{AsRawFd, RawFd}; - -libc_bitflags! { - pub struct SfdFlags: libc::c_int { - SFD_NONBLOCK; - SFD_CLOEXEC; - } -} - -pub const SIGNALFD_NEW: RawFd = -1; -#[deprecated(since = "0.23.0", note = "use mem::size_of::<siginfo>() instead")] -pub const SIGNALFD_SIGINFO_SIZE: usize = mem::size_of::<siginfo>(); - -/// Creates a new file descriptor for reading signals. -/// -/// **Important:** please read the module level documentation about signal discarding before using -/// this function! -/// -/// The `mask` parameter specifies the set of signals that can be accepted via this file descriptor. -/// -/// A signal must be blocked on every thread in a process, otherwise it won't be visible from -/// signalfd (the default handler will be invoked instead). -/// -/// See [the signalfd man page for more information](https://man7.org/linux/man-pages/man2/signalfd.2.html) -pub fn signalfd(fd: RawFd, mask: &SigSet, flags: SfdFlags) -> Result<RawFd> { - unsafe { - Errno::result(libc::signalfd( - fd as libc::c_int, - mask.as_ref(), - flags.bits(), - )) - } -} - -/// A helper struct for creating, reading and closing a `signalfd` instance. -/// -/// **Important:** please read the module level documentation about signal discarding before using -/// this struct! -/// -/// # Examples -/// -/// ``` -/// # use nix::sys::signalfd::*; -/// // Set the thread to block the SIGUSR1 signal, otherwise the default handler will be used -/// let mut mask = SigSet::empty(); -/// mask.add(signal::SIGUSR1); -/// mask.thread_block().unwrap(); -/// -/// // Signals are queued up on the file descriptor -/// let mut sfd = SignalFd::with_flags(&mask, SfdFlags::SFD_NONBLOCK).unwrap(); -/// -/// match sfd.read_signal() { -/// // we caught a signal -/// Ok(Some(sig)) => (), -/// // there were no signals waiting (only happens when the SFD_NONBLOCK flag is set, -/// // otherwise the read_signal call blocks) -/// Ok(None) => (), -/// Err(err) => (), // some error happend -/// } -/// ``` -#[derive(Debug, Eq, Hash, PartialEq)] -pub struct SignalFd(RawFd); - -impl SignalFd { - pub fn new(mask: &SigSet) -> Result<SignalFd> { - Self::with_flags(mask, SfdFlags::empty()) - } - - pub fn with_flags(mask: &SigSet, flags: SfdFlags) -> Result<SignalFd> { - let fd = signalfd(SIGNALFD_NEW, mask, flags)?; - - Ok(SignalFd(fd)) - } - - pub fn set_mask(&mut self, mask: &SigSet) -> Result<()> { - signalfd(self.0, mask, SfdFlags::empty()).map(drop) - } - - pub fn read_signal(&mut self) -> Result<Option<siginfo>> { - let mut buffer = mem::MaybeUninit::<siginfo>::uninit(); - - let size = mem::size_of_val(&buffer); - let res = Errno::result(unsafe { - libc::read(self.0, buffer.as_mut_ptr() as *mut libc::c_void, size) - }) - .map(|r| r as usize); - match res { - Ok(x) if x == size => Ok(Some(unsafe { buffer.assume_init() })), - Ok(_) => unreachable!("partial read on signalfd"), - Err(Errno::EAGAIN) => Ok(None), - Err(error) => Err(error), - } - } -} - -impl Drop for SignalFd { - fn drop(&mut self) { - let e = unistd::close(self.0); - if !std::thread::panicking() && e == Err(Errno::EBADF) { - panic!("Closing an invalid file descriptor!"); - }; - } -} - -impl AsRawFd for SignalFd { - fn as_raw_fd(&self) -> RawFd { - self.0 - } -} - -impl Iterator for SignalFd { - type Item = siginfo; - - fn next(&mut self) -> Option<Self::Item> { - match self.read_signal() { - Ok(Some(sig)) => Some(sig), - Ok(None) | Err(_) => None, - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn create_signalfd() { - let mask = SigSet::empty(); - SignalFd::new(&mask).unwrap(); - } - - #[test] - fn create_signalfd_with_opts() { - let mask = SigSet::empty(); - SignalFd::with_flags( - &mask, - SfdFlags::SFD_CLOEXEC | SfdFlags::SFD_NONBLOCK, - ) - .unwrap(); - } - - #[test] - fn read_empty_signalfd() { - let mask = SigSet::empty(); - let mut fd = - SignalFd::with_flags(&mask, SfdFlags::SFD_NONBLOCK).unwrap(); - - let res = fd.read_signal(); - assert!(res.unwrap().is_none()); - } -} diff --git a/vendor/nix/src/sys/socket/addr.rs b/vendor/nix/src/sys/socket/addr.rs deleted file mode 100644 index 4e565a5b6..000000000 --- a/vendor/nix/src/sys/socket/addr.rs +++ /dev/null @@ -1,3247 +0,0 @@ -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "haiku", - target_os = "fuchsia" -))] -#[cfg(feature = "net")] -pub use self::datalink::LinkAddr; -#[cfg(any(target_os = "android", target_os = "linux"))] -pub use self::vsock::VsockAddr; -use super::sa_family_t; -use crate::errno::Errno; -#[cfg(any(target_os = "android", target_os = "linux"))] -use crate::sys::socket::addr::alg::AlgAddr; -#[cfg(any(target_os = "android", target_os = "linux"))] -use crate::sys::socket::addr::netlink::NetlinkAddr; -#[cfg(all( - feature = "ioctl", - any(target_os = "ios", target_os = "macos") -))] -use crate::sys::socket::addr::sys_control::SysControlAddr; -use crate::{NixPath, Result}; -use cfg_if::cfg_if; -use memoffset::offset_of; -use std::convert::TryInto; -use std::ffi::OsStr; -use std::hash::{Hash, Hasher}; -use std::os::unix::ffi::OsStrExt; -#[cfg(any(target_os = "ios", target_os = "macos"))] -use std::os::unix::io::RawFd; -use std::path::Path; -use std::{fmt, mem, net, ptr, slice}; - -/// Convert a std::net::Ipv4Addr into the libc form. -#[cfg(feature = "net")] -pub(crate) const fn ipv4addr_to_libc(addr: net::Ipv4Addr) -> libc::in_addr { - static_assertions::assert_eq_size!(net::Ipv4Addr, libc::in_addr); - // Safe because both types have the same memory layout, and no fancy Drop - // impls. - unsafe { - mem::transmute(addr) - } -} - -/// Convert a std::net::Ipv6Addr into the libc form. -#[cfg(feature = "net")] -pub(crate) const fn ipv6addr_to_libc(addr: &net::Ipv6Addr) -> libc::in6_addr { - static_assertions::assert_eq_size!(net::Ipv6Addr, libc::in6_addr); - // Safe because both are Newtype wrappers around the same libc type - unsafe { - mem::transmute(*addr) - } -} - -/// These constants specify the protocol family to be used -/// in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html) -/// -/// # References -/// -/// [address_families(7)](https://man7.org/linux/man-pages/man7/address_families.7.html) -// Should this be u8? -#[repr(i32)] -#[non_exhaustive] -#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] -pub enum AddressFamily { - /// Local communication (see [`unix(7)`](https://man7.org/linux/man-pages/man7/unix.7.html)) - Unix = libc::AF_UNIX, - /// IPv4 Internet protocols (see [`ip(7)`](https://man7.org/linux/man-pages/man7/ip.7.html)) - Inet = libc::AF_INET, - /// IPv6 Internet protocols (see [`ipv6(7)`](https://man7.org/linux/man-pages/man7/ipv6.7.html)) - Inet6 = libc::AF_INET6, - /// Kernel user interface device (see [`netlink(7)`](https://man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Netlink = libc::AF_NETLINK, - /// Low level packet interface (see [`packet(7)`](https://man7.org/linux/man-pages/man7/packet.7.html)) - #[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "illumos", - target_os = "fuchsia", - target_os = "solaris" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Packet = libc::AF_PACKET, - /// KEXT Controls and Notifications - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - System = libc::AF_SYSTEM, - /// Amateur radio AX.25 protocol - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Ax25 = libc::AF_AX25, - /// IPX - Novell protocols - Ipx = libc::AF_IPX, - /// AppleTalk - AppleTalk = libc::AF_APPLETALK, - /// AX.25 packet layer protocol. - /// (see [netrom(4)](https://www.unix.com/man-page/linux/4/netrom/)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NetRom = libc::AF_NETROM, - /// Can't be used for creating sockets; mostly used for bridge - /// links in - /// [rtnetlink(7)](https://man7.org/linux/man-pages/man7/rtnetlink.7.html) - /// protocol commands. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Bridge = libc::AF_BRIDGE, - /// Access to raw ATM PVCs - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - AtmPvc = libc::AF_ATMPVC, - /// ITU-T X.25 / ISO-8208 protocol (see [`x25(7)`](https://man7.org/linux/man-pages/man7/x25.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - X25 = libc::AF_X25, - /// RATS (Radio Amateur Telecommunications Society) Open - /// Systems environment (ROSE) AX.25 packet layer protocol. - /// (see [netrom(4)](https://www.unix.com/man-page/linux/4/netrom/)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Rose = libc::AF_ROSE, - /// DECet protocol sockets. - #[cfg(not(target_os = "haiku"))] - Decnet = libc::AF_DECnet, - /// Reserved for "802.2LLC project"; never used. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NetBeui = libc::AF_NETBEUI, - /// This was a short-lived (between Linux 2.1.30 and - /// 2.1.99pre2) protocol family for firewall upcalls. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Security = libc::AF_SECURITY, - /// Key management protocol. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Key = libc::AF_KEY, - #[allow(missing_docs)] // Not documented anywhere that I can find - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Ash = libc::AF_ASH, - /// Acorn Econet protocol - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Econet = libc::AF_ECONET, - /// Access to ATM Switched Virtual Circuits - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - AtmSvc = libc::AF_ATMSVC, - /// Reliable Datagram Sockets (RDS) protocol - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Rds = libc::AF_RDS, - /// IBM SNA - #[cfg(not(target_os = "haiku"))] - Sna = libc::AF_SNA, - /// Socket interface over IrDA - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Irda = libc::AF_IRDA, - /// Generic PPP transport layer, for setting up L2 tunnels (L2TP and PPPoE) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Pppox = libc::AF_PPPOX, - /// Legacy protocol for wide area network (WAN) connectivity that was used - /// by Sangoma WAN cards - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Wanpipe = libc::AF_WANPIPE, - /// Logical link control (IEEE 802.2 LLC) protocol - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Llc = libc::AF_LLC, - /// InfiniBand native addressing - #[cfg(all(target_os = "linux", not(target_env = "uclibc")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Ib = libc::AF_IB, - /// Multiprotocol Label Switching - #[cfg(all(target_os = "linux", not(target_env = "uclibc")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Mpls = libc::AF_MPLS, - /// Controller Area Network automotive bus protocol - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Can = libc::AF_CAN, - /// TIPC, "cluster domain sockets" protocol - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Tipc = libc::AF_TIPC, - /// Bluetooth low-level socket protocol - #[cfg(not(any( - target_os = "illumos", - target_os = "ios", - target_os = "macos", - target_os = "solaris" - )))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Bluetooth = libc::AF_BLUETOOTH, - /// IUCV (inter-user communication vehicle) z/VM protocol for - /// hypervisor-guest interaction - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Iucv = libc::AF_IUCV, - /// Rx, Andrew File System remote procedure call protocol - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - RxRpc = libc::AF_RXRPC, - /// New "modular ISDN" driver interface protocol - #[cfg(not(any( - target_os = "illumos", - target_os = "solaris", - target_os = "haiku" - )))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Isdn = libc::AF_ISDN, - /// Nokia cellular modem IPC/RPC interface - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Phonet = libc::AF_PHONET, - /// IEEE 802.15.4 WPAN (wireless personal area network) raw packet protocol - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Ieee802154 = libc::AF_IEEE802154, - /// Ericsson's Communication CPU to Application CPU interface (CAIF) - /// protocol. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Caif = libc::AF_CAIF, - /// Interface to kernel crypto API - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Alg = libc::AF_ALG, - /// Near field communication - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - Nfc = libc::AF_NFC, - /// VMWare VSockets protocol for hypervisor-guest interaction. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Vsock = libc::AF_VSOCK, - /// ARPANet IMP addresses - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ImpLink = libc::AF_IMPLINK, - /// PUP protocols, e.g. BSP - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Pup = libc::AF_PUP, - /// MIT CHAOS protocols - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Chaos = libc::AF_CHAOS, - /// Novell and Xerox protocol - #[cfg(any( - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Ns = libc::AF_NS, - #[allow(missing_docs)] // Not documented anywhere that I can find - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Iso = libc::AF_ISO, - /// Bell Labs virtual circuit switch ? - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Datakit = libc::AF_DATAKIT, - /// CCITT protocols, X.25 etc - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Ccitt = libc::AF_CCITT, - /// DEC Direct data link interface - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Dli = libc::AF_DLI, - #[allow(missing_docs)] // Not documented anywhere that I can find - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Lat = libc::AF_LAT, - /// NSC Hyperchannel - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Hylink = libc::AF_HYLINK, - /// Link layer interface - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Link = libc::AF_LINK, - /// connection-oriented IP, aka ST II - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Coip = libc::AF_COIP, - /// Computer Network Technology - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Cnt = libc::AF_CNT, - /// Native ATM access - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Natm = libc::AF_NATM, - /// Unspecified address family, (see [`getaddrinfo(3)`](https://man7.org/linux/man-pages/man3/getaddrinfo.3.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Unspec = libc::AF_UNSPEC, -} - -impl AddressFamily { - /// Create a new `AddressFamily` from an integer value retrieved from `libc`, usually from - /// the `sa_family` field of a `sockaddr`. - /// - /// Currently only supports these address families: Unix, Inet (v4 & v6), Netlink, Link/Packet - /// and System. Returns None for unsupported or unknown address families. - pub const fn from_i32(family: i32) -> Option<AddressFamily> { - match family { - libc::AF_UNIX => Some(AddressFamily::Unix), - libc::AF_INET => Some(AddressFamily::Inet), - libc::AF_INET6 => Some(AddressFamily::Inet6), - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_NETLINK => Some(AddressFamily::Netlink), - #[cfg(any(target_os = "macos", target_os = "macos"))] - libc::AF_SYSTEM => Some(AddressFamily::System), - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_PACKET => Some(AddressFamily::Packet), - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "illumos", - target_os = "openbsd" - ))] - libc::AF_LINK => Some(AddressFamily::Link), - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_VSOCK => Some(AddressFamily::Vsock), - _ => None, - } - } -} - -feature! { -#![feature = "net"] - -#[deprecated( - since = "0.24.0", - note = "use SockaddrIn, SockaddrIn6, or SockaddrStorage instead" -)] -#[allow(missing_docs)] // Since they're all deprecated anyway -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum InetAddr { - V4(libc::sockaddr_in), - V6(libc::sockaddr_in6), -} - -#[allow(missing_docs)] // It's deprecated anyway -#[allow(deprecated)] -impl InetAddr { - #[allow(clippy::needless_update)] // It isn't needless on all OSes - pub fn from_std(std: &net::SocketAddr) -> InetAddr { - match *std { - net::SocketAddr::V4(ref addr) => { - InetAddr::V4(libc::sockaddr_in { - #[cfg(any(target_os = "dragonfly", target_os = "freebsd", - target_os = "haiku", target_os = "hermit", - target_os = "ios", target_os = "macos", - target_os = "netbsd", target_os = "openbsd"))] - sin_len: mem::size_of::<libc::sockaddr_in>() as u8, - sin_family: AddressFamily::Inet as sa_family_t, - sin_port: addr.port().to_be(), // network byte order - sin_addr: Ipv4Addr::from_std(addr.ip()).0, - .. unsafe { mem::zeroed() } - }) - } - net::SocketAddr::V6(ref addr) => { - InetAddr::V6(libc::sockaddr_in6 { - #[cfg(any(target_os = "dragonfly", target_os = "freebsd", - target_os = "haiku", target_os = "hermit", - target_os = "ios", target_os = "macos", - target_os = "netbsd", target_os = "openbsd"))] - sin6_len: mem::size_of::<libc::sockaddr_in6>() as u8, - sin6_family: AddressFamily::Inet6 as sa_family_t, - sin6_port: addr.port().to_be(), // network byte order - sin6_addr: Ipv6Addr::from_std(addr.ip()).0, - sin6_flowinfo: addr.flowinfo(), // host byte order - sin6_scope_id: addr.scope_id(), // host byte order - .. unsafe { mem::zeroed() } - }) - } - } - } - - #[allow(clippy::needless_update)] // It isn't needless on all OSes - pub fn new(ip: IpAddr, port: u16) -> InetAddr { - match ip { - IpAddr::V4(ref ip) => { - InetAddr::V4(libc::sockaddr_in { - sin_family: AddressFamily::Inet as sa_family_t, - sin_port: port.to_be(), - sin_addr: ip.0, - .. unsafe { mem::zeroed() } - }) - } - IpAddr::V6(ref ip) => { - InetAddr::V6(libc::sockaddr_in6 { - sin6_family: AddressFamily::Inet6 as sa_family_t, - sin6_port: port.to_be(), - sin6_addr: ip.0, - .. unsafe { mem::zeroed() } - }) - } - } - } - /// Gets the IP address associated with this socket address. - pub const fn ip(&self) -> IpAddr { - match *self { - InetAddr::V4(ref sa) => IpAddr::V4(Ipv4Addr(sa.sin_addr)), - InetAddr::V6(ref sa) => IpAddr::V6(Ipv6Addr(sa.sin6_addr)), - } - } - - /// Gets the port number associated with this socket address - pub const fn port(&self) -> u16 { - match *self { - InetAddr::V6(ref sa) => u16::from_be(sa.sin6_port), - InetAddr::V4(ref sa) => u16::from_be(sa.sin_port), - } - } - - pub fn to_std(&self) -> net::SocketAddr { - match *self { - InetAddr::V4(ref sa) => net::SocketAddr::V4( - net::SocketAddrV4::new( - Ipv4Addr(sa.sin_addr).to_std(), - self.port())), - InetAddr::V6(ref sa) => net::SocketAddr::V6( - net::SocketAddrV6::new( - Ipv6Addr(sa.sin6_addr).to_std(), - self.port(), - sa.sin6_flowinfo, - sa.sin6_scope_id)), - } - } - - #[deprecated(since = "0.23.0", note = "use .to_string() instead")] - pub fn to_str(&self) -> String { - format!("{}", self) - } -} - -#[allow(deprecated)] -impl fmt::Display for InetAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - InetAddr::V4(_) => write!(f, "{}:{}", self.ip(), self.port()), - InetAddr::V6(_) => write!(f, "[{}]:{}", self.ip(), self.port()), - } - } -} - -/* - * - * ===== IpAddr ===== - * - */ -#[allow(missing_docs)] // Since they're all deprecated anyway -#[allow(deprecated)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -#[deprecated( - since = "0.24.0", - note = "Use std::net::IpAddr instead" -)] -pub enum IpAddr { - V4(Ipv4Addr), - V6(Ipv6Addr), -} - -#[allow(deprecated)] -#[allow(missing_docs)] // Since they're all deprecated anyway -impl IpAddr { - /// Create a new IpAddr that contains an IPv4 address. - /// - /// The result will represent the IP address a.b.c.d - pub const fn new_v4(a: u8, b: u8, c: u8, d: u8) -> IpAddr { - IpAddr::V4(Ipv4Addr::new(a, b, c, d)) - } - - /// Create a new IpAddr that contains an IPv6 address. - /// - /// The result will represent the IP address a:b:c:d:e:f - #[allow(clippy::many_single_char_names)] - #[allow(clippy::too_many_arguments)] - pub const fn new_v6(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> IpAddr { - IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g, h)) - } - - pub fn from_std(std: &net::IpAddr) -> IpAddr { - match *std { - net::IpAddr::V4(ref std) => IpAddr::V4(Ipv4Addr::from_std(std)), - net::IpAddr::V6(ref std) => IpAddr::V6(Ipv6Addr::from_std(std)), - } - } - - pub const fn to_std(&self) -> net::IpAddr { - match *self { - IpAddr::V4(ref ip) => net::IpAddr::V4(ip.to_std()), - IpAddr::V6(ref ip) => net::IpAddr::V6(ip.to_std()), - } - } -} - -#[allow(deprecated)] -impl fmt::Display for IpAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - IpAddr::V4(ref v4) => v4.fmt(f), - IpAddr::V6(ref v6) => v6.fmt(f) - } - } -} - -/* - * - * ===== Ipv4Addr ===== - * - */ - -#[deprecated( - since = "0.24.0", - note = "Use std::net::Ipv4Addr instead" -)] -#[allow(missing_docs)] // Since they're all deprecated anyway -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -#[repr(transparent)] -pub struct Ipv4Addr(pub libc::in_addr); - -#[allow(deprecated)] -#[allow(missing_docs)] // Since they're all deprecated anyway -impl Ipv4Addr { - #[allow(clippy::identity_op)] // More readable this way - pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { - let ip = (((a as u32) << 24) | - ((b as u32) << 16) | - ((c as u32) << 8) | - ((d as u32) << 0)).to_be(); - - Ipv4Addr(libc::in_addr { s_addr: ip }) - } - - // Use pass by reference for symmetry with Ipv6Addr::from_std - #[allow(clippy::trivially_copy_pass_by_ref)] - pub fn from_std(std: &net::Ipv4Addr) -> Ipv4Addr { - let bits = std.octets(); - Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3]) - } - - pub const fn any() -> Ipv4Addr { - Ipv4Addr(libc::in_addr { s_addr: libc::INADDR_ANY }) - } - - pub const fn octets(self) -> [u8; 4] { - let bits = u32::from_be(self.0.s_addr); - [(bits >> 24) as u8, (bits >> 16) as u8, (bits >> 8) as u8, bits as u8] - } - - pub const fn to_std(self) -> net::Ipv4Addr { - let bits = self.octets(); - net::Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3]) - } -} - -#[allow(deprecated)] -impl fmt::Display for Ipv4Addr { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let octets = self.octets(); - write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]) - } -} - -/* - * - * ===== Ipv6Addr ===== - * - */ - -#[deprecated( - since = "0.24.0", - note = "Use std::net::Ipv6Addr instead" -)] -#[allow(missing_docs)] // Since they're all deprecated anyway -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -#[repr(transparent)] -pub struct Ipv6Addr(pub libc::in6_addr); - -// Note that IPv6 addresses are stored in big endian order on all architectures. -// See https://tools.ietf.org/html/rfc1700 or consult your favorite search -// engine. - -macro_rules! to_u8_array { - ($($num:ident),*) => { - [ $(($num>>8) as u8, ($num&0xff) as u8,)* ] - } -} - -macro_rules! to_u16_array { - ($slf:ident, $($first:expr, $second:expr),*) => { - [$( (($slf.0.s6_addr[$first] as u16) << 8) + $slf.0.s6_addr[$second] as u16,)*] - } -} - -#[allow(deprecated)] -#[allow(missing_docs)] // Since they're all deprecated anyway -impl Ipv6Addr { - #[allow(clippy::many_single_char_names)] - #[allow(clippy::too_many_arguments)] - pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr { - Ipv6Addr(libc::in6_addr{s6_addr: to_u8_array!(a,b,c,d,e,f,g,h)}) - } - - pub fn from_std(std: &net::Ipv6Addr) -> Ipv6Addr { - let s = std.segments(); - Ipv6Addr::new(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7]) - } - - /// Return the eight 16-bit segments that make up this address - pub const fn segments(&self) -> [u16; 8] { - to_u16_array!(self, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15) - } - - pub const fn to_std(&self) -> net::Ipv6Addr { - let s = self.segments(); - net::Ipv6Addr::new(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7]) - } -} - -#[allow(deprecated)] -impl fmt::Display for Ipv6Addr { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - self.to_std().fmt(fmt) - } -} -} - -/// A wrapper around `sockaddr_un`. -#[derive(Clone, Copy, Debug)] -#[repr(C)] -pub struct UnixAddr { - // INVARIANT: sun & sun_len are valid as defined by docs for from_raw_parts - sun: libc::sockaddr_un, - /// The length of the valid part of `sun`, including the sun_family field - /// but excluding any trailing nul. - // On the BSDs, this field is built into sun - #[cfg(any( - target_os = "android", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux" - ))] - sun_len: u8, -} - -// linux man page unix(7) says there are 3 kinds of unix socket: -// pathname: addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(sun_path) + 1 -// unnamed: addrlen = sizeof(sa_family_t) -// abstract: addren > sizeof(sa_family_t), name = sun_path[..(addrlen - sizeof(sa_family_t))] -// -// what we call path_len = addrlen - offsetof(struct sockaddr_un, sun_path) -#[derive(PartialEq, Eq, Hash)] -enum UnixAddrKind<'a> { - Pathname(&'a Path), - Unnamed, - #[cfg(any(target_os = "android", target_os = "linux"))] - Abstract(&'a [u8]), -} -impl<'a> UnixAddrKind<'a> { - /// Safety: sun & sun_len must be valid - unsafe fn get(sun: &'a libc::sockaddr_un, sun_len: u8) -> Self { - assert!(sun_len as usize >= offset_of!(libc::sockaddr_un, sun_path)); - let path_len = - sun_len as usize - offset_of!(libc::sockaddr_un, sun_path); - if path_len == 0 { - return Self::Unnamed; - } - #[cfg(any(target_os = "android", target_os = "linux"))] - if sun.sun_path[0] == 0 { - let name = slice::from_raw_parts( - sun.sun_path.as_ptr().add(1) as *const u8, - path_len - 1, - ); - return Self::Abstract(name); - } - let pathname = - slice::from_raw_parts(sun.sun_path.as_ptr() as *const u8, path_len); - if pathname.last() == Some(&0) { - // A trailing NUL is not considered part of the path, and it does - // not need to be included in the addrlen passed to functions like - // bind(). However, Linux adds a trailing NUL, even if one was not - // originally present, when returning addrs from functions like - // getsockname() (the BSDs do not do that). So we need to filter - // out any trailing NUL here, so sockaddrs can round-trip through - // the kernel and still compare equal. - Self::Pathname(Path::new(OsStr::from_bytes( - &pathname[0..pathname.len() - 1], - ))) - } else { - Self::Pathname(Path::new(OsStr::from_bytes(pathname))) - } - } -} - -impl UnixAddr { - /// Create a new sockaddr_un representing a filesystem path. - pub fn new<P: ?Sized + NixPath>(path: &P) -> Result<UnixAddr> { - path.with_nix_path(|cstr| unsafe { - let mut ret = libc::sockaddr_un { - sun_family: AddressFamily::Unix as sa_family_t, - ..mem::zeroed() - }; - - let bytes = cstr.to_bytes(); - - if bytes.len() >= ret.sun_path.len() { - return Err(Errno::ENAMETOOLONG); - } - - let sun_len = (bytes.len() - + offset_of!(libc::sockaddr_un, sun_path)) - .try_into() - .unwrap(); - - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - { - ret.sun_len = sun_len; - } - ptr::copy_nonoverlapping( - bytes.as_ptr(), - ret.sun_path.as_mut_ptr() as *mut u8, - bytes.len(), - ); - - Ok(UnixAddr::from_raw_parts(ret, sun_len)) - })? - } - - /// Create a new `sockaddr_un` representing an address in the "abstract namespace". - /// - /// The leading nul byte for the abstract namespace is automatically added; - /// thus the input `path` is expected to be the bare name, not NUL-prefixed. - /// This is a Linux-specific extension, primarily used to allow chrooted - /// processes to communicate with processes having a different filesystem view. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn new_abstract(path: &[u8]) -> Result<UnixAddr> { - unsafe { - let mut ret = libc::sockaddr_un { - sun_family: AddressFamily::Unix as sa_family_t, - ..mem::zeroed() - }; - - if path.len() >= ret.sun_path.len() { - return Err(Errno::ENAMETOOLONG); - } - let sun_len = - (path.len() + 1 + offset_of!(libc::sockaddr_un, sun_path)) - .try_into() - .unwrap(); - - // Abstract addresses are represented by sun_path[0] == - // b'\0', so copy starting one byte in. - ptr::copy_nonoverlapping( - path.as_ptr(), - ret.sun_path.as_mut_ptr().offset(1) as *mut u8, - path.len(), - ); - - Ok(UnixAddr::from_raw_parts(ret, sun_len)) - } - } - - /// Create a new `sockaddr_un` representing an "unnamed" unix socket address. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn new_unnamed() -> UnixAddr { - let ret = libc::sockaddr_un { - sun_family: AddressFamily::Unix as sa_family_t, - .. unsafe { mem::zeroed() } - }; - - let sun_len: u8 = offset_of!(libc::sockaddr_un, sun_path).try_into().unwrap(); - - unsafe { UnixAddr::from_raw_parts(ret, sun_len) } - } - - /// Create a UnixAddr from a raw `sockaddr_un` struct and a size. `sun_len` - /// is the size of the valid portion of the struct, excluding any trailing - /// NUL. - /// - /// # Safety - /// This pair of sockaddr_un & sun_len must be a valid unix addr, which - /// means: - /// - sun_len >= offset_of(sockaddr_un, sun_path) - /// - sun_len <= sockaddr_un.sun_path.len() - offset_of(sockaddr_un, sun_path) - /// - if this is a unix addr with a pathname, sun.sun_path is a - /// fs path, not necessarily nul-terminated. - pub(crate) unsafe fn from_raw_parts( - sun: libc::sockaddr_un, - sun_len: u8, - ) -> UnixAddr { - cfg_if! { - if #[cfg(any(target_os = "android", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux" - ))] - { - UnixAddr { sun, sun_len } - } else { - assert_eq!(sun_len, sun.sun_len); - UnixAddr {sun} - } - } - } - - fn kind(&self) -> UnixAddrKind<'_> { - // SAFETY: our sockaddr is always valid because of the invariant on the struct - unsafe { UnixAddrKind::get(&self.sun, self.sun_len()) } - } - - /// If this address represents a filesystem path, return that path. - pub fn path(&self) -> Option<&Path> { - match self.kind() { - UnixAddrKind::Pathname(path) => Some(path), - _ => None, - } - } - - /// If this address represents an abstract socket, return its name. - /// - /// For abstract sockets only the bare name is returned, without the - /// leading NUL byte. `None` is returned for unnamed or path-backed sockets. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn as_abstract(&self) -> Option<&[u8]> { - match self.kind() { - UnixAddrKind::Abstract(name) => Some(name), - _ => None, - } - } - - /// Check if this address is an "unnamed" unix socket address. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - #[inline] - pub fn is_unnamed(&self) -> bool { - matches!(self.kind(), UnixAddrKind::Unnamed) - } - - /// Returns the addrlen of this socket - `offsetof(struct sockaddr_un, sun_path)` - #[inline] - pub fn path_len(&self) -> usize { - self.sun_len() as usize - offset_of!(libc::sockaddr_un, sun_path) - } - /// Returns a pointer to the raw `sockaddr_un` struct - #[inline] - pub fn as_ptr(&self) -> *const libc::sockaddr_un { - &self.sun - } - /// Returns a mutable pointer to the raw `sockaddr_un` struct - #[inline] - pub fn as_mut_ptr(&mut self) -> *mut libc::sockaddr_un { - &mut self.sun - } - - fn sun_len(&self) -> u8 { - cfg_if! { - if #[cfg(any(target_os = "android", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux" - ))] - { - self.sun_len - } else { - self.sun.sun_len - } - } - } -} - -impl private::SockaddrLikePriv for UnixAddr {} -impl SockaddrLike for UnixAddr { - #[cfg(any( - target_os = "android", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux" - ))] - fn len(&self) -> libc::socklen_t { - self.sun_len.into() - } - - unsafe fn from_raw( - addr: *const libc::sockaddr, - len: Option<libc::socklen_t>, - ) -> Option<Self> - where - Self: Sized, - { - if let Some(l) = len { - if (l as usize) < offset_of!(libc::sockaddr_un, sun_path) - || l > u8::MAX as libc::socklen_t - { - return None; - } - } - if (*addr).sa_family as i32 != libc::AF_UNIX { - return None; - } - let mut su: libc::sockaddr_un = mem::zeroed(); - let sup = &mut su as *mut libc::sockaddr_un as *mut u8; - cfg_if! { - if #[cfg(any(target_os = "android", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux" - ))] { - let su_len = len.unwrap_or( - mem::size_of::<libc::sockaddr_un>() as libc::socklen_t - ); - } else { - let su_len = len.unwrap_or((*addr).sa_len as libc::socklen_t); - } - }; - ptr::copy(addr as *const u8, sup, su_len as usize); - Some(Self::from_raw_parts(su, su_len as u8)) - } - - fn size() -> libc::socklen_t - where - Self: Sized, - { - mem::size_of::<libc::sockaddr_un>() as libc::socklen_t - } -} - -impl AsRef<libc::sockaddr_un> for UnixAddr { - fn as_ref(&self) -> &libc::sockaddr_un { - &self.sun - } -} - -#[cfg(any(target_os = "android", target_os = "linux"))] -fn fmt_abstract(abs: &[u8], f: &mut fmt::Formatter) -> fmt::Result { - use fmt::Write; - f.write_str("@\"")?; - for &b in abs { - use fmt::Display; - char::from(b).escape_default().fmt(f)?; - } - f.write_char('"')?; - Ok(()) -} - -impl fmt::Display for UnixAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self.kind() { - UnixAddrKind::Pathname(path) => path.display().fmt(f), - UnixAddrKind::Unnamed => f.pad("<unbound UNIX socket>"), - #[cfg(any(target_os = "android", target_os = "linux"))] - UnixAddrKind::Abstract(name) => fmt_abstract(name, f), - } - } -} - -impl PartialEq for UnixAddr { - fn eq(&self, other: &UnixAddr) -> bool { - self.kind() == other.kind() - } -} - -impl Eq for UnixAddr {} - -impl Hash for UnixAddr { - fn hash<H: Hasher>(&self, s: &mut H) { - self.kind().hash(s) - } -} - -/// Anything that, in C, can be cast back and forth to `sockaddr`. -/// -/// Most implementors also implement `AsRef<libc::XXX>` to access their -/// inner type read-only. -#[allow(clippy::len_without_is_empty)] -pub trait SockaddrLike: private::SockaddrLikePriv { - /// Returns a raw pointer to the inner structure. Useful for FFI. - fn as_ptr(&self) -> *const libc::sockaddr { - self as *const Self as *const libc::sockaddr - } - - /// Unsafe constructor from a variable length source - /// - /// Some C APIs from provide `len`, and others do not. If it's provided it - /// will be validated. If not, it will be guessed based on the family. - /// - /// # Arguments - /// - /// - `addr`: raw pointer to something that can be cast to a - /// `libc::sockaddr`. For example, `libc::sockaddr_in`, - /// `libc::sockaddr_in6`, etc. - /// - `len`: For fixed-width types like `sockaddr_in`, it will be - /// validated if present and ignored if not. For variable-width - /// types it is required and must be the total length of valid - /// data. For example, if `addr` points to a - /// named `sockaddr_un`, then `len` must be the length of the - /// structure up to but not including the trailing NUL. - /// - /// # Safety - /// - /// `addr` must be valid for the specific type of sockaddr. `len`, if - /// present, must not exceed the length of valid data in `addr`. - unsafe fn from_raw( - addr: *const libc::sockaddr, - len: Option<libc::socklen_t>, - ) -> Option<Self> - where - Self: Sized; - - /// Return the address family of this socket - /// - /// # Examples - /// One common use is to match on the family of a union type, like this: - /// ``` - /// # use nix::sys::socket::*; - /// let fd = socket(AddressFamily::Inet, SockType::Stream, - /// SockFlag::empty(), None).unwrap(); - /// let ss: SockaddrStorage = getsockname(fd).unwrap(); - /// match ss.family().unwrap() { - /// AddressFamily::Inet => println!("{}", ss.as_sockaddr_in().unwrap()), - /// AddressFamily::Inet6 => println!("{}", ss.as_sockaddr_in6().unwrap()), - /// _ => println!("Unexpected address family") - /// } - /// ``` - fn family(&self) -> Option<AddressFamily> { - // Safe since all implementors have a sa_family field at the same - // address, and they're all repr(C) - AddressFamily::from_i32(unsafe { - (*(self as *const Self as *const libc::sockaddr)).sa_family as i32 - }) - } - - cfg_if! { - if #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] { - /// Return the length of valid data in the sockaddr structure. - /// - /// For fixed-size sockaddrs, this should be the size of the - /// structure. But for variable-sized types like [`UnixAddr`] it - /// may be less. - fn len(&self) -> libc::socklen_t { - // Safe since all implementors have a sa_len field at the same - // address, and they're all repr(transparent). - // Robust for all implementors. - unsafe { - (*(self as *const Self as *const libc::sockaddr)).sa_len - }.into() - } - } else { - /// Return the length of valid data in the sockaddr structure. - /// - /// For fixed-size sockaddrs, this should be the size of the - /// structure. But for variable-sized types like [`UnixAddr`] it - /// may be less. - fn len(&self) -> libc::socklen_t { - // No robust default implementation is possible without an - // sa_len field. Implementors with a variable size must - // override this method. - mem::size_of_val(self) as libc::socklen_t - } - } - } - - /// Return the available space in the structure - fn size() -> libc::socklen_t - where - Self: Sized, - { - mem::size_of::<Self>() as libc::socklen_t - } -} - -impl private::SockaddrLikePriv for () { - fn as_mut_ptr(&mut self) -> *mut libc::sockaddr { - ptr::null_mut() - } -} - -/// `()` can be used in place of a real Sockaddr when no address is expected, -/// for example for a field of `Option<S> where S: SockaddrLike`. -// If this RFC ever stabilizes, then ! will be a better choice. -// https://github.com/rust-lang/rust/issues/35121 -impl SockaddrLike for () { - fn as_ptr(&self) -> *const libc::sockaddr { - ptr::null() - } - - unsafe fn from_raw( - _: *const libc::sockaddr, - _: Option<libc::socklen_t>, - ) -> Option<Self> - where - Self: Sized, - { - None - } - - fn family(&self) -> Option<AddressFamily> { - None - } - - fn len(&self) -> libc::socklen_t { - 0 - } -} - -/// An IPv4 socket address -// This is identical to net::SocketAddrV4. But the standard library -// doesn't allow direct access to the libc fields, which we need. So we -// reimplement it here. -#[cfg(feature = "net")] -#[repr(transparent)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct SockaddrIn(libc::sockaddr_in); - -#[cfg(feature = "net")] -impl SockaddrIn { - /// Returns the IP address associated with this socket address, in native - /// endian. - pub const fn ip(&self) -> libc::in_addr_t { - u32::from_be(self.0.sin_addr.s_addr) - } - - /// Creates a new socket address from IPv4 octets and a port number. - pub fn new(a: u8, b: u8, c: u8, d: u8, port: u16) -> Self { - Self(libc::sockaddr_in { - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "haiku", - target_os = "openbsd" - ))] - sin_len: Self::size() as u8, - sin_family: AddressFamily::Inet as sa_family_t, - sin_port: u16::to_be(port), - sin_addr: libc::in_addr { - s_addr: u32::from_ne_bytes([a, b, c, d]), - }, - sin_zero: unsafe { mem::zeroed() }, - }) - } - - /// Returns the port number associated with this socket address, in native - /// endian. - pub const fn port(&self) -> u16 { - u16::from_be(self.0.sin_port) - } -} - -#[cfg(feature = "net")] -impl private::SockaddrLikePriv for SockaddrIn {} -#[cfg(feature = "net")] -impl SockaddrLike for SockaddrIn { - unsafe fn from_raw( - addr: *const libc::sockaddr, - len: Option<libc::socklen_t>, - ) -> Option<Self> - where - Self: Sized, - { - if let Some(l) = len { - if l != mem::size_of::<libc::sockaddr_in>() as libc::socklen_t { - return None; - } - } - if (*addr).sa_family as i32 != libc::AF_INET { - return None; - } - Some(Self(ptr::read_unaligned(addr as *const _))) - } -} - -#[cfg(feature = "net")] -impl AsRef<libc::sockaddr_in> for SockaddrIn { - fn as_ref(&self) -> &libc::sockaddr_in { - &self.0 - } -} - -#[cfg(feature = "net")] -impl fmt::Display for SockaddrIn { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let ne = u32::from_be(self.0.sin_addr.s_addr); - let port = u16::from_be(self.0.sin_port); - write!( - f, - "{}.{}.{}.{}:{}", - ne >> 24, - (ne >> 16) & 0xFF, - (ne >> 8) & 0xFF, - ne & 0xFF, - port - ) - } -} - -#[cfg(feature = "net")] -impl From<net::SocketAddrV4> for SockaddrIn { - fn from(addr: net::SocketAddrV4) -> Self { - Self(libc::sockaddr_in { - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "haiku", - target_os = "hermit", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - sin_len: mem::size_of::<libc::sockaddr_in>() as u8, - sin_family: AddressFamily::Inet as sa_family_t, - sin_port: addr.port().to_be(), // network byte order - sin_addr: ipv4addr_to_libc(*addr.ip()), - ..unsafe { mem::zeroed() } - }) - } -} - -#[cfg(feature = "net")] -impl From<SockaddrIn> for net::SocketAddrV4 { - fn from(addr: SockaddrIn) -> Self { - net::SocketAddrV4::new( - net::Ipv4Addr::from(addr.0.sin_addr.s_addr.to_ne_bytes()), - u16::from_be(addr.0.sin_port), - ) - } -} - -#[cfg(feature = "net")] -impl std::str::FromStr for SockaddrIn { - type Err = net::AddrParseError; - - fn from_str(s: &str) -> std::result::Result<Self, Self::Err> { - net::SocketAddrV4::from_str(s).map(SockaddrIn::from) - } -} - -/// An IPv6 socket address -#[cfg(feature = "net")] -#[repr(transparent)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct SockaddrIn6(libc::sockaddr_in6); - -#[cfg(feature = "net")] -impl SockaddrIn6 { - /// Returns the flow information associated with this address. - pub const fn flowinfo(&self) -> u32 { - self.0.sin6_flowinfo - } - - /// Returns the IP address associated with this socket address. - pub fn ip(&self) -> net::Ipv6Addr { - net::Ipv6Addr::from(self.0.sin6_addr.s6_addr) - } - - /// Returns the port number associated with this socket address, in native - /// endian. - pub const fn port(&self) -> u16 { - u16::from_be(self.0.sin6_port) - } - - /// Returns the scope ID associated with this address. - pub const fn scope_id(&self) -> u32 { - self.0.sin6_scope_id - } -} - -#[cfg(feature = "net")] -impl private::SockaddrLikePriv for SockaddrIn6 {} -#[cfg(feature = "net")] -impl SockaddrLike for SockaddrIn6 { - unsafe fn from_raw( - addr: *const libc::sockaddr, - len: Option<libc::socklen_t>, - ) -> Option<Self> - where - Self: Sized, - { - if let Some(l) = len { - if l != mem::size_of::<libc::sockaddr_in6>() as libc::socklen_t { - return None; - } - } - if (*addr).sa_family as i32 != libc::AF_INET6 { - return None; - } - Some(Self(ptr::read_unaligned(addr as *const _))) - } -} - -#[cfg(feature = "net")] -impl AsRef<libc::sockaddr_in6> for SockaddrIn6 { - fn as_ref(&self) -> &libc::sockaddr_in6 { - &self.0 - } -} - -#[cfg(feature = "net")] -impl fmt::Display for SockaddrIn6 { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // These things are really hard to display properly. Easier to let std - // do it. - let std = net::SocketAddrV6::new( - self.ip(), - self.port(), - self.flowinfo(), - self.scope_id(), - ); - std.fmt(f) - } -} - -#[cfg(feature = "net")] -impl From<net::SocketAddrV6> for SockaddrIn6 { - fn from(addr: net::SocketAddrV6) -> Self { - #[allow(clippy::needless_update)] // It isn't needless on Illumos - Self(libc::sockaddr_in6 { - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "haiku", - target_os = "hermit", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - sin6_len: mem::size_of::<libc::sockaddr_in6>() as u8, - sin6_family: AddressFamily::Inet6 as sa_family_t, - sin6_port: addr.port().to_be(), // network byte order - sin6_addr: ipv6addr_to_libc(addr.ip()), - sin6_flowinfo: addr.flowinfo(), // host byte order - sin6_scope_id: addr.scope_id(), // host byte order - ..unsafe { mem::zeroed() } - }) - } -} - -#[cfg(feature = "net")] -impl From<SockaddrIn6> for net::SocketAddrV6 { - fn from(addr: SockaddrIn6) -> Self { - net::SocketAddrV6::new( - net::Ipv6Addr::from(addr.0.sin6_addr.s6_addr), - u16::from_be(addr.0.sin6_port), - addr.0.sin6_flowinfo, - addr.0.sin6_scope_id, - ) - } -} - -#[cfg(feature = "net")] -impl std::str::FromStr for SockaddrIn6 { - type Err = net::AddrParseError; - - fn from_str(s: &str) -> std::result::Result<Self, Self::Err> { - net::SocketAddrV6::from_str(s).map(SockaddrIn6::from) - } -} - -/// A container for any sockaddr type -/// -/// Just like C's `sockaddr_storage`, this type is large enough to hold any type -/// of sockaddr. It can be used as an argument with functions like -/// [`bind`](super::bind) and [`getsockname`](super::getsockname). Though it is -/// a union, it can be safely accessed through the `as_*` methods. -/// -/// # Example -/// ``` -/// # use nix::sys::socket::*; -/// # use std::str::FromStr; -/// let localhost = SockaddrIn::from_str("127.0.0.1:8081").unwrap(); -/// let fd = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), -/// None).unwrap(); -/// bind(fd, &localhost).expect("bind"); -/// let ss: SockaddrStorage = getsockname(fd).expect("getsockname"); -/// assert_eq!(&localhost, ss.as_sockaddr_in().unwrap()); -/// ``` -#[derive(Clone, Copy, Eq)] -#[repr(C)] -pub union SockaddrStorage { - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - alg: AlgAddr, - #[cfg(feature = "net")] - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - dl: LinkAddr, - #[cfg(any(target_os = "android", target_os = "linux"))] - nl: NetlinkAddr, - #[cfg(all( - feature = "ioctl", - any(target_os = "ios", target_os = "macos") - ))] - #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))] - sctl: SysControlAddr, - #[cfg(feature = "net")] - sin: SockaddrIn, - #[cfg(feature = "net")] - sin6: SockaddrIn6, - ss: libc::sockaddr_storage, - su: UnixAddr, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - vsock: VsockAddr, -} -impl private::SockaddrLikePriv for SockaddrStorage {} -impl SockaddrLike for SockaddrStorage { - unsafe fn from_raw( - addr: *const libc::sockaddr, - l: Option<libc::socklen_t>, - ) -> Option<Self> - where - Self: Sized, - { - if addr.is_null() { - return None; - } - if let Some(len) = l { - let ulen = len as usize; - if ulen < offset_of!(libc::sockaddr, sa_data) - || ulen > mem::size_of::<libc::sockaddr_storage>() - { - None - } else { - let mut ss: libc::sockaddr_storage = mem::zeroed(); - let ssp = &mut ss as *mut libc::sockaddr_storage as *mut u8; - ptr::copy(addr as *const u8, ssp, len as usize); - #[cfg(any( - target_os = "android", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux" - ))] - if i32::from(ss.ss_family) == libc::AF_UNIX { - // Safe because we UnixAddr is strictly smaller than - // SockaddrStorage, and we just initialized the structure. - (*(&mut ss as *mut libc::sockaddr_storage as *mut UnixAddr)).sun_len = len as u8; - } - Some(Self { ss }) - } - } else { - // If length is not available and addr is of a fixed-length type, - // copy it. If addr is of a variable length type and len is not - // available, then there's nothing we can do. - match (*addr).sa_family as i32 { - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_ALG => { - AlgAddr::from_raw(addr, l).map(|alg| Self { alg }) - } - #[cfg(feature = "net")] - libc::AF_INET => { - SockaddrIn::from_raw(addr, l).map(|sin| Self { sin }) - } - #[cfg(feature = "net")] - libc::AF_INET6 => { - SockaddrIn6::from_raw(addr, l).map(|sin6| Self { sin6 }) - } - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "haiku", - target_os = "openbsd" - ))] - #[cfg(feature = "net")] - libc::AF_LINK => { - LinkAddr::from_raw(addr, l).map(|dl| Self { dl }) - } - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_NETLINK => { - NetlinkAddr::from_raw(addr, l).map(|nl| Self { nl }) - } - #[cfg(any( - target_os = "android", - target_os = "fuchsia", - target_os = "linux" - ))] - #[cfg(feature = "net")] - libc::AF_PACKET => { - LinkAddr::from_raw(addr, l).map(|dl| Self { dl }) - } - #[cfg(all( - feature = "ioctl", - any(target_os = "ios", target_os = "macos") - ))] - libc::AF_SYSTEM => { - SysControlAddr::from_raw(addr, l).map(|sctl| Self { sctl }) - } - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_VSOCK => { - VsockAddr::from_raw(addr, l).map(|vsock| Self { vsock }) - } - _ => None, - } - } - } - - #[cfg(any( - target_os = "android", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux" - ))] - fn len(&self) -> libc::socklen_t { - match self.as_unix_addr() { - // The UnixAddr type knows its own length - Some(ua) => ua.len(), - // For all else, we're just a boring SockaddrStorage - None => mem::size_of_val(self) as libc::socklen_t - } - } -} - -macro_rules! accessors { - ( - $fname:ident, - $fname_mut:ident, - $sockty:ty, - $family:expr, - $libc_ty:ty, - $field:ident) => { - /// Safely and falliably downcast to an immutable reference - pub fn $fname(&self) -> Option<&$sockty> { - if self.family() == Some($family) - && self.len() >= mem::size_of::<$libc_ty>() as libc::socklen_t - { - // Safe because family and len are validated - Some(unsafe { &self.$field }) - } else { - None - } - } - - /// Safely and falliably downcast to a mutable reference - pub fn $fname_mut(&mut self) -> Option<&mut $sockty> { - if self.family() == Some($family) - && self.len() >= mem::size_of::<$libc_ty>() as libc::socklen_t - { - // Safe because family and len are validated - Some(unsafe { &mut self.$field }) - } else { - None - } - } - }; -} - -impl SockaddrStorage { - /// Downcast to an immutable `[UnixAddr]` reference. - pub fn as_unix_addr(&self) -> Option<&UnixAddr> { - cfg_if! { - if #[cfg(any(target_os = "android", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux" - ))] - { - let p = unsafe{ &self.ss as *const libc::sockaddr_storage }; - // Safe because UnixAddr is strictly smaller than - // sockaddr_storage, and we're fully initialized - let len = unsafe { - (*(p as *const UnixAddr )).sun_len as usize - }; - } else { - let len = self.len() as usize; - } - } - // Sanity checks - if self.family() != Some(AddressFamily::Unix) || - len < offset_of!(libc::sockaddr_un, sun_path) || - len > mem::size_of::<libc::sockaddr_un>() { - None - } else { - Some(unsafe{&self.su}) - } - } - - /// Downcast to a mutable `[UnixAddr]` reference. - pub fn as_unix_addr_mut(&mut self) -> Option<&mut UnixAddr> { - cfg_if! { - if #[cfg(any(target_os = "android", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux" - ))] - { - let p = unsafe{ &self.ss as *const libc::sockaddr_storage }; - // Safe because UnixAddr is strictly smaller than - // sockaddr_storage, and we're fully initialized - let len = unsafe { - (*(p as *const UnixAddr )).sun_len as usize - }; - } else { - let len = self.len() as usize; - } - } - // Sanity checks - if self.family() != Some(AddressFamily::Unix) || - len < offset_of!(libc::sockaddr_un, sun_path) || - len > mem::size_of::<libc::sockaddr_un>() { - None - } else { - Some(unsafe{&mut self.su}) - } - } - - #[cfg(any(target_os = "android", target_os = "linux"))] - accessors! {as_alg_addr, as_alg_addr_mut, AlgAddr, - AddressFamily::Alg, libc::sockaddr_alg, alg} - - #[cfg(any( - target_os = "android", - target_os = "fuchsia", - target_os = "linux" - ))] - #[cfg(feature = "net")] - accessors! { - as_link_addr, as_link_addr_mut, LinkAddr, - AddressFamily::Packet, libc::sockaddr_ll, dl} - - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg(feature = "net")] - accessors! { - as_link_addr, as_link_addr_mut, LinkAddr, - AddressFamily::Link, libc::sockaddr_dl, dl} - - #[cfg(feature = "net")] - accessors! { - as_sockaddr_in, as_sockaddr_in_mut, SockaddrIn, - AddressFamily::Inet, libc::sockaddr_in, sin} - - #[cfg(feature = "net")] - accessors! { - as_sockaddr_in6, as_sockaddr_in6_mut, SockaddrIn6, - AddressFamily::Inet6, libc::sockaddr_in6, sin6} - - #[cfg(any(target_os = "android", target_os = "linux"))] - accessors! {as_netlink_addr, as_netlink_addr_mut, NetlinkAddr, - AddressFamily::Netlink, libc::sockaddr_nl, nl} - - #[cfg(all(feature = "ioctl", any(target_os = "ios", target_os = "macos")))] - #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))] - accessors! {as_sys_control_addr, as_sys_control_addr_mut, SysControlAddr, - AddressFamily::System, libc::sockaddr_ctl, sctl} - - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - accessors! {as_vsock_addr, as_vsock_addr_mut, VsockAddr, - AddressFamily::Vsock, libc::sockaddr_vm, vsock} -} - -impl fmt::Debug for SockaddrStorage { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("SockaddrStorage") - // Safe because sockaddr_storage has the least specific - // field types - .field("ss", unsafe { &self.ss }) - .finish() - } -} - -impl fmt::Display for SockaddrStorage { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - unsafe { - match self.ss.ss_family as i32 { - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_ALG => self.alg.fmt(f), - #[cfg(feature = "net")] - libc::AF_INET => self.sin.fmt(f), - #[cfg(feature = "net")] - libc::AF_INET6 => self.sin6.fmt(f), - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg(feature = "net")] - libc::AF_LINK => self.dl.fmt(f), - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_NETLINK => self.nl.fmt(f), - #[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "fuchsia" - ))] - #[cfg(feature = "net")] - libc::AF_PACKET => self.dl.fmt(f), - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg(feature = "ioctl")] - libc::AF_SYSTEM => self.sctl.fmt(f), - libc::AF_UNIX => self.su.fmt(f), - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_VSOCK => self.vsock.fmt(f), - _ => "<Address family unspecified>".fmt(f), - } - } - } -} - -#[cfg(feature = "net")] -impl From<net::SocketAddrV4> for SockaddrStorage { - fn from(s: net::SocketAddrV4) -> Self { - unsafe { - let mut ss: Self = mem::zeroed(); - ss.sin = SockaddrIn::from(s); - ss - } - } -} - -#[cfg(feature = "net")] -impl From<net::SocketAddrV6> for SockaddrStorage { - fn from(s: net::SocketAddrV6) -> Self { - unsafe { - let mut ss: Self = mem::zeroed(); - ss.sin6 = SockaddrIn6::from(s); - ss - } - } -} - -#[cfg(feature = "net")] -impl From<net::SocketAddr> for SockaddrStorage { - fn from(s: net::SocketAddr) -> Self { - match s { - net::SocketAddr::V4(sa4) => Self::from(sa4), - net::SocketAddr::V6(sa6) => Self::from(sa6), - } - } -} - -impl Hash for SockaddrStorage { - fn hash<H: Hasher>(&self, s: &mut H) { - unsafe { - match self.ss.ss_family as i32 { - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_ALG => self.alg.hash(s), - #[cfg(feature = "net")] - libc::AF_INET => self.sin.hash(s), - #[cfg(feature = "net")] - libc::AF_INET6 => self.sin6.hash(s), - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg(feature = "net")] - libc::AF_LINK => self.dl.hash(s), - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_NETLINK => self.nl.hash(s), - #[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "fuchsia" - ))] - #[cfg(feature = "net")] - libc::AF_PACKET => self.dl.hash(s), - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg(feature = "ioctl")] - libc::AF_SYSTEM => self.sctl.hash(s), - libc::AF_UNIX => self.su.hash(s), - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_VSOCK => self.vsock.hash(s), - _ => self.ss.hash(s), - } - } - } -} - -impl PartialEq for SockaddrStorage { - fn eq(&self, other: &Self) -> bool { - unsafe { - match (self.ss.ss_family as i32, other.ss.ss_family as i32) { - #[cfg(any(target_os = "android", target_os = "linux"))] - (libc::AF_ALG, libc::AF_ALG) => self.alg == other.alg, - #[cfg(feature = "net")] - (libc::AF_INET, libc::AF_INET) => self.sin == other.sin, - #[cfg(feature = "net")] - (libc::AF_INET6, libc::AF_INET6) => self.sin6 == other.sin6, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg(feature = "net")] - (libc::AF_LINK, libc::AF_LINK) => self.dl == other.dl, - #[cfg(any(target_os = "android", target_os = "linux"))] - (libc::AF_NETLINK, libc::AF_NETLINK) => self.nl == other.nl, - #[cfg(any( - target_os = "android", - target_os = "fuchsia", - target_os = "linux" - ))] - #[cfg(feature = "net")] - (libc::AF_PACKET, libc::AF_PACKET) => self.dl == other.dl, - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg(feature = "ioctl")] - (libc::AF_SYSTEM, libc::AF_SYSTEM) => self.sctl == other.sctl, - (libc::AF_UNIX, libc::AF_UNIX) => self.su == other.su, - #[cfg(any(target_os = "android", target_os = "linux"))] - (libc::AF_VSOCK, libc::AF_VSOCK) => self.vsock == other.vsock, - _ => false, - } - } - } -} - -mod private { - pub trait SockaddrLikePriv { - /// Returns a mutable raw pointer to the inner structure. - /// - /// # Safety - /// - /// This method is technically safe, but modifying the inner structure's - /// `family` or `len` fields may result in violating Nix's invariants. - /// It is best to use this method only with foreign functions that do - /// not change the sockaddr type. - fn as_mut_ptr(&mut self) -> *mut libc::sockaddr { - self as *mut Self as *mut libc::sockaddr - } - } -} - -/// Represents a socket address -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -#[deprecated( - since = "0.24.0", - note = "use SockaddrLike or SockaddrStorage instead" -)] -#[allow(missing_docs)] // Since they're all deprecated anyway -#[allow(deprecated)] -#[non_exhaustive] -pub enum SockAddr { - #[cfg(feature = "net")] - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - Inet(InetAddr), - Unix(UnixAddr), - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Netlink(NetlinkAddr), - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Alg(AlgAddr), - #[cfg(all( - feature = "ioctl", - any(target_os = "ios", target_os = "macos") - ))] - #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))] - SysControl(SysControlAddr), - /// Datalink address (MAC) - #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg(feature = "net")] - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - Link(LinkAddr), - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Vsock(VsockAddr), -} - -#[allow(missing_docs)] // Since they're all deprecated anyway -#[allow(deprecated)] -impl SockAddr { - feature! { - #![feature = "net"] - pub fn new_inet(addr: InetAddr) -> SockAddr { - SockAddr::Inet(addr) - } - } - - pub fn new_unix<P: ?Sized + NixPath>(path: &P) -> Result<SockAddr> { - Ok(SockAddr::Unix(UnixAddr::new(path)?)) - } - - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn new_netlink(pid: u32, groups: u32) -> SockAddr { - SockAddr::Netlink(NetlinkAddr::new(pid, groups)) - } - - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn new_alg(alg_type: &str, alg_name: &str) -> SockAddr { - SockAddr::Alg(AlgAddr::new(alg_type, alg_name)) - } - - feature! { - #![feature = "ioctl"] - #[cfg(any(target_os = "ios", target_os = "macos"))] - pub fn new_sys_control(sockfd: RawFd, name: &str, unit: u32) -> Result<SockAddr> { - SysControlAddr::from_name(sockfd, name, unit).map(SockAddr::SysControl) - } - } - - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn new_vsock(cid: u32, port: u32) -> SockAddr { - SockAddr::Vsock(VsockAddr::new(cid, port)) - } - - pub fn family(&self) -> AddressFamily { - match *self { - #[cfg(feature = "net")] - SockAddr::Inet(InetAddr::V4(..)) => AddressFamily::Inet, - #[cfg(feature = "net")] - SockAddr::Inet(InetAddr::V6(..)) => AddressFamily::Inet6, - SockAddr::Unix(..) => AddressFamily::Unix, - #[cfg(any(target_os = "android", target_os = "linux"))] - SockAddr::Netlink(..) => AddressFamily::Netlink, - #[cfg(any(target_os = "android", target_os = "linux"))] - SockAddr::Alg(..) => AddressFamily::Alg, - #[cfg(all( - feature = "ioctl", - any(target_os = "ios", target_os = "macos") - ))] - SockAddr::SysControl(..) => AddressFamily::System, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg(feature = "net")] - SockAddr::Link(..) => AddressFamily::Packet, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "illumos", - target_os = "openbsd" - ))] - #[cfg(feature = "net")] - SockAddr::Link(..) => AddressFamily::Link, - #[cfg(any(target_os = "android", target_os = "linux"))] - SockAddr::Vsock(..) => AddressFamily::Vsock, - } - } - - #[deprecated(since = "0.23.0", note = "use .to_string() instead")] - pub fn to_str(&self) -> String { - format!("{}", self) - } - - /// Creates a `SockAddr` struct from libc's sockaddr. - /// - /// Supports only the following address families: Unix, Inet (v4 & v6), Netlink and System. - /// Returns None for unsupported families. - /// - /// # Safety - /// - /// unsafe because it takes a raw pointer as argument. The caller must - /// ensure that the pointer is valid. - #[cfg(not(target_os = "fuchsia"))] - #[cfg(feature = "net")] - pub(crate) unsafe fn from_libc_sockaddr( - addr: *const libc::sockaddr, - ) -> Option<SockAddr> { - if addr.is_null() { - None - } else { - match AddressFamily::from_i32(i32::from((*addr).sa_family)) { - Some(AddressFamily::Unix) => None, - #[cfg(feature = "net")] - Some(AddressFamily::Inet) => Some(SockAddr::Inet( - InetAddr::V4(ptr::read_unaligned(addr as *const _)), - )), - #[cfg(feature = "net")] - Some(AddressFamily::Inet6) => Some(SockAddr::Inet( - InetAddr::V6(ptr::read_unaligned(addr as *const _)), - )), - #[cfg(any(target_os = "android", target_os = "linux"))] - Some(AddressFamily::Netlink) => Some(SockAddr::Netlink( - NetlinkAddr(ptr::read_unaligned(addr as *const _)), - )), - #[cfg(all( - feature = "ioctl", - any(target_os = "ios", target_os = "macos") - ))] - Some(AddressFamily::System) => Some(SockAddr::SysControl( - SysControlAddr(ptr::read_unaligned(addr as *const _)), - )), - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg(feature = "net")] - Some(AddressFamily::Packet) => Some(SockAddr::Link(LinkAddr( - ptr::read_unaligned(addr as *const _), - ))), - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "illumos", - target_os = "openbsd" - ))] - #[cfg(feature = "net")] - Some(AddressFamily::Link) => { - let ether_addr = - LinkAddr(ptr::read_unaligned(addr as *const _)); - if ether_addr.is_empty() { - None - } else { - Some(SockAddr::Link(ether_addr)) - } - } - #[cfg(any(target_os = "android", target_os = "linux"))] - Some(AddressFamily::Vsock) => Some(SockAddr::Vsock(VsockAddr( - ptr::read_unaligned(addr as *const _), - ))), - // Other address families are currently not supported and simply yield a None - // entry instead of a proper conversion to a `SockAddr`. - Some(_) | None => None, - } - } - } - - /// Conversion from nix's SockAddr type to the underlying libc sockaddr type. - /// - /// This is useful for interfacing with other libc functions that don't yet have nix wrappers. - /// Returns a reference to the underlying data type (as a sockaddr reference) along - /// with the size of the actual data type. sockaddr is commonly used as a proxy for - /// a superclass as C doesn't support inheritance, so many functions that take - /// a sockaddr * need to take the size of the underlying type as well and then internally cast it back. - pub fn as_ffi_pair(&self) -> (&libc::sockaddr, libc::socklen_t) { - match *self { - #[cfg(feature = "net")] - SockAddr::Inet(InetAddr::V4(ref addr)) => ( - // This cast is always allowed in C - unsafe { - &*(addr as *const libc::sockaddr_in - as *const libc::sockaddr) - }, - mem::size_of_val(addr) as libc::socklen_t, - ), - #[cfg(feature = "net")] - SockAddr::Inet(InetAddr::V6(ref addr)) => ( - // This cast is always allowed in C - unsafe { - &*(addr as *const libc::sockaddr_in6 - as *const libc::sockaddr) - }, - mem::size_of_val(addr) as libc::socklen_t, - ), - SockAddr::Unix(ref unix_addr) => ( - // This cast is always allowed in C - unsafe { - &*(&unix_addr.sun as *const libc::sockaddr_un - as *const libc::sockaddr) - }, - unix_addr.sun_len() as libc::socklen_t, - ), - #[cfg(any(target_os = "android", target_os = "linux"))] - SockAddr::Netlink(NetlinkAddr(ref sa)) => ( - // This cast is always allowed in C - unsafe { - &*(sa as *const libc::sockaddr_nl as *const libc::sockaddr) - }, - mem::size_of_val(sa) as libc::socklen_t, - ), - #[cfg(any(target_os = "android", target_os = "linux"))] - SockAddr::Alg(AlgAddr(ref sa)) => ( - // This cast is always allowed in C - unsafe { - &*(sa as *const libc::sockaddr_alg as *const libc::sockaddr) - }, - mem::size_of_val(sa) as libc::socklen_t, - ), - #[cfg(all( - feature = "ioctl", - any(target_os = "ios", target_os = "macos") - ))] - SockAddr::SysControl(SysControlAddr(ref sa)) => ( - // This cast is always allowed in C - unsafe { - &*(sa as *const libc::sockaddr_ctl as *const libc::sockaddr) - }, - mem::size_of_val(sa) as libc::socklen_t, - ), - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg(feature = "net")] - SockAddr::Link(LinkAddr(ref addr)) => ( - // This cast is always allowed in C - unsafe { - &*(addr as *const libc::sockaddr_ll - as *const libc::sockaddr) - }, - mem::size_of_val(addr) as libc::socklen_t, - ), - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg(feature = "net")] - SockAddr::Link(LinkAddr(ref addr)) => ( - // This cast is always allowed in C - unsafe { - &*(addr as *const libc::sockaddr_dl - as *const libc::sockaddr) - }, - mem::size_of_val(addr) as libc::socklen_t, - ), - #[cfg(any(target_os = "android", target_os = "linux"))] - SockAddr::Vsock(VsockAddr(ref sa)) => ( - // This cast is always allowed in C - unsafe { - &*(sa as *const libc::sockaddr_vm as *const libc::sockaddr) - }, - mem::size_of_val(sa) as libc::socklen_t, - ), - } - } -} - -#[allow(deprecated)] -impl fmt::Display for SockAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - #[cfg(feature = "net")] - SockAddr::Inet(ref inet) => inet.fmt(f), - SockAddr::Unix(ref unix) => unix.fmt(f), - #[cfg(any(target_os = "android", target_os = "linux"))] - SockAddr::Netlink(ref nl) => nl.fmt(f), - #[cfg(any(target_os = "android", target_os = "linux"))] - SockAddr::Alg(ref nl) => nl.fmt(f), - #[cfg(all( - feature = "ioctl", - any(target_os = "ios", target_os = "macos") - ))] - SockAddr::SysControl(ref sc) => sc.fmt(f), - #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "illumos", - target_os = "openbsd" - ))] - #[cfg(feature = "net")] - SockAddr::Link(ref ether_addr) => ether_addr.fmt(f), - #[cfg(any(target_os = "android", target_os = "linux"))] - SockAddr::Vsock(ref svm) => svm.fmt(f), - } - } -} - -#[cfg(not(target_os = "fuchsia"))] -#[cfg(feature = "net")] -#[allow(deprecated)] -impl private::SockaddrLikePriv for SockAddr {} -#[cfg(not(target_os = "fuchsia"))] -#[cfg(feature = "net")] -#[allow(deprecated)] -impl SockaddrLike for SockAddr { - unsafe fn from_raw( - addr: *const libc::sockaddr, - _len: Option<libc::socklen_t>, - ) -> Option<Self> { - Self::from_libc_sockaddr(addr) - } -} - -#[cfg(any(target_os = "android", target_os = "linux"))] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub mod netlink { - use super::*; - use crate::sys::socket::addr::AddressFamily; - use libc::{sa_family_t, sockaddr_nl}; - use std::{fmt, mem}; - - /// Address for the Linux kernel user interface device. - /// - /// # References - /// - /// [netlink(7)](https://man7.org/linux/man-pages/man7/netlink.7.html) - #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)] - #[repr(transparent)] - pub struct NetlinkAddr(pub(in super::super) sockaddr_nl); - - impl NetlinkAddr { - /// Construct a new socket address from its port ID and multicast groups - /// mask. - pub fn new(pid: u32, groups: u32) -> NetlinkAddr { - let mut addr: sockaddr_nl = unsafe { mem::zeroed() }; - addr.nl_family = AddressFamily::Netlink as sa_family_t; - addr.nl_pid = pid; - addr.nl_groups = groups; - - NetlinkAddr(addr) - } - - /// Return the socket's port ID. - pub const fn pid(&self) -> u32 { - self.0.nl_pid - } - - /// Return the socket's multicast groups mask - pub const fn groups(&self) -> u32 { - self.0.nl_groups - } - } - - impl private::SockaddrLikePriv for NetlinkAddr {} - impl SockaddrLike for NetlinkAddr { - unsafe fn from_raw( - addr: *const libc::sockaddr, - len: Option<libc::socklen_t>, - ) -> Option<Self> - where - Self: Sized, - { - if let Some(l) = len { - if l != mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t { - return None; - } - } - if (*addr).sa_family as i32 != libc::AF_NETLINK { - return None; - } - Some(Self(ptr::read_unaligned(addr as *const _))) - } - } - - impl AsRef<libc::sockaddr_nl> for NetlinkAddr { - fn as_ref(&self) -> &libc::sockaddr_nl { - &self.0 - } - } - - impl fmt::Display for NetlinkAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "pid: {} groups: {}", self.pid(), self.groups()) - } - } -} - -#[cfg(any(target_os = "android", target_os = "linux"))] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub mod alg { - use super::*; - use libc::{c_char, sockaddr_alg, AF_ALG}; - use std::ffi::CStr; - use std::hash::{Hash, Hasher}; - use std::{fmt, mem, str}; - - /// Socket address for the Linux kernel crypto API - #[derive(Copy, Clone)] - #[repr(transparent)] - pub struct AlgAddr(pub(in super::super) sockaddr_alg); - - impl private::SockaddrLikePriv for AlgAddr {} - impl SockaddrLike for AlgAddr { - unsafe fn from_raw( - addr: *const libc::sockaddr, - l: Option<libc::socklen_t>, - ) -> Option<Self> - where - Self: Sized, - { - if let Some(l) = l { - if l != mem::size_of::<libc::sockaddr_alg>() as libc::socklen_t - { - return None; - } - } - if (*addr).sa_family as i32 != libc::AF_ALG { - return None; - } - Some(Self(ptr::read_unaligned(addr as *const _))) - } - } - - impl AsRef<libc::sockaddr_alg> for AlgAddr { - fn as_ref(&self) -> &libc::sockaddr_alg { - &self.0 - } - } - - // , PartialEq, Eq, Debug, Hash - impl PartialEq for AlgAddr { - fn eq(&self, other: &Self) -> bool { - let (inner, other) = (self.0, other.0); - ( - inner.salg_family, - &inner.salg_type[..], - inner.salg_feat, - inner.salg_mask, - &inner.salg_name[..], - ) == ( - other.salg_family, - &other.salg_type[..], - other.salg_feat, - other.salg_mask, - &other.salg_name[..], - ) - } - } - - impl Eq for AlgAddr {} - - impl Hash for AlgAddr { - fn hash<H: Hasher>(&self, s: &mut H) { - let inner = self.0; - ( - inner.salg_family, - &inner.salg_type[..], - inner.salg_feat, - inner.salg_mask, - &inner.salg_name[..], - ) - .hash(s); - } - } - - impl AlgAddr { - /// Construct an `AF_ALG` socket from its cipher name and type. - pub fn new(alg_type: &str, alg_name: &str) -> AlgAddr { - let mut addr: sockaddr_alg = unsafe { mem::zeroed() }; - addr.salg_family = AF_ALG as u16; - addr.salg_type[..alg_type.len()] - .copy_from_slice(alg_type.to_string().as_bytes()); - addr.salg_name[..alg_name.len()] - .copy_from_slice(alg_name.to_string().as_bytes()); - - AlgAddr(addr) - } - - /// Return the socket's cipher type, for example `hash` or `aead`. - pub fn alg_type(&self) -> &CStr { - unsafe { - CStr::from_ptr(self.0.salg_type.as_ptr() as *const c_char) - } - } - - /// Return the socket's cipher name, for example `sha1`. - pub fn alg_name(&self) -> &CStr { - unsafe { - CStr::from_ptr(self.0.salg_name.as_ptr() as *const c_char) - } - } - } - - impl fmt::Display for AlgAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "type: {} alg: {}", - self.alg_name().to_string_lossy(), - self.alg_type().to_string_lossy() - ) - } - } - - impl fmt::Debug for AlgAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(self, f) - } - } -} - -feature! { -#![feature = "ioctl"] -#[cfg(any(target_os = "ios", target_os = "macos"))] -pub mod sys_control { - use crate::sys::socket::addr::AddressFamily; - use libc::{self, c_uchar}; - use std::{fmt, mem, ptr}; - use std::os::unix::io::RawFd; - use crate::{Errno, Result}; - use super::{private, SockaddrLike}; - - // FIXME: Move type into `libc` - #[repr(C)] - #[derive(Clone, Copy)] - #[allow(missing_debug_implementations)] - pub struct ctl_ioc_info { - pub ctl_id: u32, - pub ctl_name: [c_uchar; MAX_KCTL_NAME], - } - - const CTL_IOC_MAGIC: u8 = b'N'; - const CTL_IOC_INFO: u8 = 3; - const MAX_KCTL_NAME: usize = 96; - - ioctl_readwrite!(ctl_info, CTL_IOC_MAGIC, CTL_IOC_INFO, ctl_ioc_info); - - /// Apple system control socket - /// - /// # References - /// - /// <https://developer.apple.com/documentation/kernel/sockaddr_ctl> - #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] - #[repr(transparent)] - pub struct SysControlAddr(pub(in super::super) libc::sockaddr_ctl); - - impl private::SockaddrLikePriv for SysControlAddr {} - impl SockaddrLike for SysControlAddr { - unsafe fn from_raw(addr: *const libc::sockaddr, len: Option<libc::socklen_t>) - -> Option<Self> where Self: Sized - { - if let Some(l) = len { - if l != mem::size_of::<libc::sockaddr_ctl>() as libc::socklen_t { - return None; - } - } - if (*addr).sa_family as i32 != libc::AF_SYSTEM { - return None; - } - Some(Self(ptr::read_unaligned(addr as *const _))) - } - } - - impl AsRef<libc::sockaddr_ctl> for SysControlAddr { - fn as_ref(&self) -> &libc::sockaddr_ctl { - &self.0 - } - } - - impl SysControlAddr { - /// Construct a new `SysControlAddr` from its kernel unique identifier - /// and unit number. - pub const fn new(id: u32, unit: u32) -> SysControlAddr { - let addr = libc::sockaddr_ctl { - sc_len: mem::size_of::<libc::sockaddr_ctl>() as c_uchar, - sc_family: AddressFamily::System as c_uchar, - ss_sysaddr: libc::AF_SYS_CONTROL as u16, - sc_id: id, - sc_unit: unit, - sc_reserved: [0; 5] - }; - - SysControlAddr(addr) - } - - /// Construct a new `SysControlAddr` from its human readable name and - /// unit number. - pub fn from_name(sockfd: RawFd, name: &str, unit: u32) -> Result<SysControlAddr> { - if name.len() > MAX_KCTL_NAME { - return Err(Errno::ENAMETOOLONG); - } - - let mut ctl_name = [0; MAX_KCTL_NAME]; - ctl_name[..name.len()].clone_from_slice(name.as_bytes()); - let mut info = ctl_ioc_info { ctl_id: 0, ctl_name }; - - unsafe { ctl_info(sockfd, &mut info)?; } - - Ok(SysControlAddr::new(info.ctl_id, unit)) - } - - /// Return the kernel unique identifier - pub const fn id(&self) -> u32 { - self.0.sc_id - } - - /// Return the kernel controller private unit number. - pub const fn unit(&self) -> u32 { - self.0.sc_unit - } - } - - impl fmt::Display for SysControlAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(self, f) - } - } -} -} - -#[cfg(any(target_os = "android", target_os = "linux", target_os = "fuchsia"))] -#[cfg_attr(docsrs, doc(cfg(all())))] -mod datalink { - feature! { - #![feature = "net"] - use super::{fmt, mem, private, ptr, SockaddrLike}; - - /// Hardware Address - #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] - #[repr(transparent)] - pub struct LinkAddr(pub(in super::super) libc::sockaddr_ll); - - impl LinkAddr { - /// Physical-layer protocol - pub fn protocol(&self) -> u16 { - self.0.sll_protocol - } - - /// Interface number - pub fn ifindex(&self) -> usize { - self.0.sll_ifindex as usize - } - - /// ARP hardware type - pub fn hatype(&self) -> u16 { - self.0.sll_hatype - } - - /// Packet type - pub fn pkttype(&self) -> u8 { - self.0.sll_pkttype - } - - /// Length of MAC address - pub fn halen(&self) -> usize { - self.0.sll_halen as usize - } - - /// Physical-layer address (MAC) - // Returns an Option just for cross-platform compatibility - pub fn addr(&self) -> Option<[u8; 6]> { - Some([ - self.0.sll_addr[0], - self.0.sll_addr[1], - self.0.sll_addr[2], - self.0.sll_addr[3], - self.0.sll_addr[4], - self.0.sll_addr[5], - ]) - } - } - - impl fmt::Display for LinkAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if let Some(addr) = self.addr() { - write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", - addr[0], - addr[1], - addr[2], - addr[3], - addr[4], - addr[5]) - } else { - Ok(()) - } - } - } - impl private::SockaddrLikePriv for LinkAddr {} - impl SockaddrLike for LinkAddr { - unsafe fn from_raw(addr: *const libc::sockaddr, - len: Option<libc::socklen_t>) - -> Option<Self> where Self: Sized - { - if let Some(l) = len { - if l != mem::size_of::<libc::sockaddr_ll>() as libc::socklen_t { - return None; - } - } - if (*addr).sa_family as i32 != libc::AF_PACKET { - return None; - } - Some(Self(ptr::read_unaligned(addr as *const _))) - } - } - - impl AsRef<libc::sockaddr_ll> for LinkAddr { - fn as_ref(&self) -> &libc::sockaddr_ll { - &self.0 - } - } - - } -} - -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "haiku", - target_os = "openbsd" -))] -#[cfg_attr(docsrs, doc(cfg(all())))] -mod datalink { - feature! { - #![feature = "net"] - use super::{fmt, mem, private, ptr, SockaddrLike}; - - /// Hardware Address - #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] - #[repr(transparent)] - pub struct LinkAddr(pub(in super::super) libc::sockaddr_dl); - - impl LinkAddr { - /// interface index, if != 0, system given index for interface - #[cfg(not(target_os = "haiku"))] - pub fn ifindex(&self) -> usize { - self.0.sdl_index as usize - } - - /// Datalink type - #[cfg(not(target_os = "haiku"))] - pub fn datalink_type(&self) -> u8 { - self.0.sdl_type - } - - /// MAC address start position - pub fn nlen(&self) -> usize { - self.0.sdl_nlen as usize - } - - /// link level address length - pub fn alen(&self) -> usize { - self.0.sdl_alen as usize - } - - /// link layer selector length - #[cfg(not(target_os = "haiku"))] - pub fn slen(&self) -> usize { - self.0.sdl_slen as usize - } - - /// if link level address length == 0, - /// or `sdl_data` not be larger. - pub fn is_empty(&self) -> bool { - let nlen = self.nlen(); - let alen = self.alen(); - let data_len = self.0.sdl_data.len(); - - alen == 0 || nlen + alen >= data_len - } - - /// Physical-layer address (MAC) - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - pub fn addr(&self) -> Option<[u8; 6]> { - let nlen = self.nlen(); - let data = self.0.sdl_data; - - if self.is_empty() { - None - } else { - Some([ - data[nlen] as u8, - data[nlen + 1] as u8, - data[nlen + 2] as u8, - data[nlen + 3] as u8, - data[nlen + 4] as u8, - data[nlen + 5] as u8, - ]) - } - } - } - - impl fmt::Display for LinkAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if let Some(addr) = self.addr() { - write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", - addr[0], - addr[1], - addr[2], - addr[3], - addr[4], - addr[5]) - } else { - Ok(()) - } - } - } - impl private::SockaddrLikePriv for LinkAddr {} - impl SockaddrLike for LinkAddr { - unsafe fn from_raw(addr: *const libc::sockaddr, - len: Option<libc::socklen_t>) - -> Option<Self> where Self: Sized - { - if let Some(l) = len { - if l != mem::size_of::<libc::sockaddr_dl>() as libc::socklen_t { - return None; - } - } - if (*addr).sa_family as i32 != libc::AF_LINK { - return None; - } - Some(Self(ptr::read_unaligned(addr as *const _))) - } - } - - impl AsRef<libc::sockaddr_dl> for LinkAddr { - fn as_ref(&self) -> &libc::sockaddr_dl { - &self.0 - } - } - - } -} - -#[cfg(any(target_os = "android", target_os = "linux"))] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub mod vsock { - use super::*; - use crate::sys::socket::addr::AddressFamily; - use libc::{sa_family_t, sockaddr_vm}; - use std::hash::{Hash, Hasher}; - use std::{fmt, mem}; - - /// Socket address for VMWare VSockets protocol - /// - /// # References - /// - /// [vsock(7)](https://man7.org/linux/man-pages/man7/vsock.7.html) - #[derive(Copy, Clone)] - #[repr(transparent)] - pub struct VsockAddr(pub(in super::super) sockaddr_vm); - - impl private::SockaddrLikePriv for VsockAddr {} - impl SockaddrLike for VsockAddr { - unsafe fn from_raw( - addr: *const libc::sockaddr, - len: Option<libc::socklen_t>, - ) -> Option<Self> - where - Self: Sized, - { - if let Some(l) = len { - if l != mem::size_of::<libc::sockaddr_vm>() as libc::socklen_t { - return None; - } - } - if (*addr).sa_family as i32 != libc::AF_VSOCK { - return None; - } - Some(Self(ptr::read_unaligned(addr as *const _))) - } - } - - impl AsRef<libc::sockaddr_vm> for VsockAddr { - fn as_ref(&self) -> &libc::sockaddr_vm { - &self.0 - } - } - - impl PartialEq for VsockAddr { - fn eq(&self, other: &Self) -> bool { - let (inner, other) = (self.0, other.0); - (inner.svm_family, inner.svm_cid, inner.svm_port) - == (other.svm_family, other.svm_cid, other.svm_port) - } - } - - impl Eq for VsockAddr {} - - impl Hash for VsockAddr { - fn hash<H: Hasher>(&self, s: &mut H) { - let inner = self.0; - (inner.svm_family, inner.svm_cid, inner.svm_port).hash(s); - } - } - - /// VSOCK Address - /// - /// The address for AF_VSOCK socket is defined as a combination of a - /// 32-bit Context Identifier (CID) and a 32-bit port number. - impl VsockAddr { - /// Construct a `VsockAddr` from its raw fields. - pub fn new(cid: u32, port: u32) -> VsockAddr { - let mut addr: sockaddr_vm = unsafe { mem::zeroed() }; - addr.svm_family = AddressFamily::Vsock as sa_family_t; - addr.svm_cid = cid; - addr.svm_port = port; - - VsockAddr(addr) - } - - /// Context Identifier (CID) - pub fn cid(&self) -> u32 { - self.0.svm_cid - } - - /// Port number - pub fn port(&self) -> u32 { - self.0.svm_port - } - } - - impl fmt::Display for VsockAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "cid: {} port: {}", self.cid(), self.port()) - } - } - - impl fmt::Debug for VsockAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(self, f) - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - mod types { - use super::*; - - #[test] - fn test_ipv4addr_to_libc() { - let s = std::net::Ipv4Addr::new(1, 2, 3, 4); - let l = ipv4addr_to_libc(s); - assert_eq!(l.s_addr, u32::to_be(0x01020304)); - } - - #[test] - fn test_ipv6addr_to_libc() { - let s = std::net::Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8); - let l = ipv6addr_to_libc(&s); - assert_eq!( - l.s6_addr, - [0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8] - ); - } - } - - mod link { - #![allow(clippy::cast_ptr_alignment)] - - #[cfg(any( - target_os = "ios", - target_os = "macos", - target_os = "illumos" - ))] - use super::super::super::socklen_t; - use super::*; - - /// Don't panic when trying to display an empty datalink address - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[test] - fn test_datalink_display() { - use super::super::LinkAddr; - use std::mem; - - let la = LinkAddr(libc::sockaddr_dl { - sdl_len: 56, - sdl_family: 18, - sdl_index: 5, - sdl_type: 24, - sdl_nlen: 3, - sdl_alen: 0, - sdl_slen: 0, - ..unsafe { mem::zeroed() } - }); - format!("{}", la); - } - - #[cfg(all( - any( - target_os = "android", - target_os = "fuchsia", - target_os = "linux" - ), - target_endian = "little" - ))] - #[test] - fn linux_loopback() { - #[repr(align(2))] - struct Raw([u8; 20]); - - let bytes = Raw([ - 17u8, 0, 0, 0, 1, 0, 0, 0, 4, 3, 0, 6, 1, 2, 3, 4, 5, 6, 0, 0, - ]); - let sa = bytes.0.as_ptr() as *const libc::sockaddr; - let len = None; - let sock_addr = - unsafe { SockaddrStorage::from_raw(sa, len) }.unwrap(); - assert_eq!(sock_addr.family(), Some(AddressFamily::Packet)); - match sock_addr.as_link_addr() { - Some(dl) => assert_eq!(dl.addr(), Some([1, 2, 3, 4, 5, 6])), - None => panic!("Can't unwrap sockaddr storage"), - } - } - - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[test] - fn macos_loopback() { - let bytes = - [20i8, 18, 1, 0, 24, 3, 0, 0, 108, 111, 48, 0, 0, 0, 0, 0]; - let sa = bytes.as_ptr() as *const libc::sockaddr; - let len = Some(bytes.len() as socklen_t); - let sock_addr = - unsafe { SockaddrStorage::from_raw(sa, len) }.unwrap(); - assert_eq!(sock_addr.family(), Some(AddressFamily::Link)); - match sock_addr.as_link_addr() { - Some(dl) => { - assert!(dl.addr().is_none()); - } - None => panic!("Can't unwrap sockaddr storage"), - } - } - - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[test] - fn macos_tap() { - let bytes = [ - 20i8, 18, 7, 0, 6, 3, 6, 0, 101, 110, 48, 24, 101, -112, -35, - 76, -80, - ]; - let ptr = bytes.as_ptr(); - let sa = ptr as *const libc::sockaddr; - let len = Some(bytes.len() as socklen_t); - - let sock_addr = - unsafe { SockaddrStorage::from_raw(sa, len).unwrap() }; - assert_eq!(sock_addr.family(), Some(AddressFamily::Link)); - match sock_addr.as_link_addr() { - Some(dl) => { - assert_eq!(dl.addr(), Some([24u8, 101, 144, 221, 76, 176])) - } - None => panic!("Can't unwrap sockaddr storage"), - } - } - - #[cfg(target_os = "illumos")] - #[test] - fn illumos_tap() { - let bytes = [25u8, 0, 0, 0, 6, 0, 6, 0, 24, 101, 144, 221, 76, 176]; - let ptr = bytes.as_ptr(); - let sa = ptr as *const libc::sockaddr; - let len = Some(bytes.len() as socklen_t); - let _sock_addr = unsafe { SockaddrStorage::from_raw(sa, len) }; - - assert!(_sock_addr.is_some()); - - let sock_addr = _sock_addr.unwrap(); - - assert_eq!(sock_addr.family().unwrap(), AddressFamily::Link); - - assert_eq!( - sock_addr.as_link_addr().unwrap().addr(), - Some([24u8, 101, 144, 221, 76, 176]) - ); - } - - #[test] - fn size() { - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "illumos", - target_os = "openbsd", - target_os = "haiku" - ))] - let l = mem::size_of::<libc::sockaddr_dl>(); - #[cfg(any( - target_os = "android", - target_os = "fuchsia", - target_os = "linux" - ))] - let l = mem::size_of::<libc::sockaddr_ll>(); - assert_eq!(LinkAddr::size() as usize, l); - } - } - - mod sockaddr_in { - use super::*; - use std::str::FromStr; - - #[test] - fn display() { - let s = "127.0.0.1:8080"; - let addr = SockaddrIn::from_str(s).unwrap(); - assert_eq!(s, format!("{}", addr)); - } - - #[test] - fn size() { - assert_eq!( - mem::size_of::<libc::sockaddr_in>(), - SockaddrIn::size() as usize - ); - } - } - - mod sockaddr_in6 { - use super::*; - use std::str::FromStr; - - #[test] - fn display() { - let s = "[1234:5678:90ab:cdef::1111:2222]:8080"; - let addr = SockaddrIn6::from_str(s).unwrap(); - assert_eq!(s, format!("{}", addr)); - } - - #[test] - fn size() { - assert_eq!( - mem::size_of::<libc::sockaddr_in6>(), - SockaddrIn6::size() as usize - ); - } - - #[test] - // Ensure that we can convert to-and-from std::net variants without change. - fn to_and_from() { - let s = "[1234:5678:90ab:cdef::1111:2222]:8080"; - let mut nix_sin6 = SockaddrIn6::from_str(s).unwrap(); - nix_sin6.0.sin6_flowinfo = 0x12345678; - nix_sin6.0.sin6_scope_id = 0x9abcdef0; - - let std_sin6 : std::net::SocketAddrV6 = nix_sin6.into(); - assert_eq!(nix_sin6, std_sin6.into()); - } - } - - mod sockaddr_storage { - use super::*; - - #[test] - fn from_sockaddr_un_named() { - let ua = UnixAddr::new("/var/run/mysock").unwrap(); - let ptr = ua.as_ptr() as *const libc::sockaddr; - let ss = unsafe { - SockaddrStorage::from_raw(ptr, Some(ua.len())) - }.unwrap(); - assert_eq!(ss.len(), ua.len()); - } - - #[cfg(any(target_os = "android", target_os = "linux"))] - #[test] - fn from_sockaddr_un_abstract_named() { - let name = String::from("nix\0abstract\0test"); - let ua = UnixAddr::new_abstract(name.as_bytes()).unwrap(); - let ptr = ua.as_ptr() as *const libc::sockaddr; - let ss = unsafe { - SockaddrStorage::from_raw(ptr, Some(ua.len())) - }.unwrap(); - assert_eq!(ss.len(), ua.len()); - } - - #[cfg(any(target_os = "android", target_os = "linux"))] - #[test] - fn from_sockaddr_un_abstract_unnamed() { - let ua = UnixAddr::new_unnamed(); - let ptr = ua.as_ptr() as *const libc::sockaddr; - let ss = unsafe { - SockaddrStorage::from_raw(ptr, Some(ua.len())) - }.unwrap(); - assert_eq!(ss.len(), ua.len()); - } - } - - mod unixaddr { - use super::*; - - #[cfg(any(target_os = "android", target_os = "linux"))] - #[test] - fn abstract_sun_path() { - let name = String::from("nix\0abstract\0test"); - let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap(); - - let sun_path1 = - unsafe { &(*addr.as_ptr()).sun_path[..addr.path_len()] }; - let sun_path2 = [ - 0, 110, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, - 116, 101, 115, 116, - ]; - assert_eq!(sun_path1, sun_path2); - } - - #[test] - fn size() { - assert_eq!( - mem::size_of::<libc::sockaddr_un>(), - UnixAddr::size() as usize - ); - } - } -} diff --git a/vendor/nix/src/sys/socket/mod.rs b/vendor/nix/src/sys/socket/mod.rs deleted file mode 100644 index 8513b6fbe..000000000 --- a/vendor/nix/src/sys/socket/mod.rs +++ /dev/null @@ -1,2487 +0,0 @@ -//! Socket interface functions -//! -//! [Further reading](https://man7.org/linux/man-pages/man7/socket.7.html) -#[cfg(target_os = "linux")] -#[cfg(feature = "uio")] -use crate::sys::time::TimeSpec; -#[cfg(feature = "uio")] -use crate::sys::time::TimeVal; -use crate::{errno::Errno, Result}; -use cfg_if::cfg_if; -use libc::{ - self, c_int, c_void, iovec, size_t, socklen_t, CMSG_DATA, CMSG_FIRSTHDR, - CMSG_LEN, CMSG_NXTHDR, -}; -use std::convert::{TryFrom, TryInto}; -use std::io::{IoSlice, IoSliceMut}; -#[cfg(feature = "net")] -use std::net; -use std::os::unix::io::RawFd; -use std::{mem, ptr, slice}; - -#[deny(missing_docs)] -mod addr; -#[deny(missing_docs)] -pub mod sockopt; - -/* - * - * ===== Re-exports ===== - * - */ - -pub use self::addr::{SockaddrLike, SockaddrStorage}; - -#[cfg(not(any(target_os = "illumos", target_os = "solaris")))] -#[allow(deprecated)] -pub use self::addr::{AddressFamily, SockAddr, UnixAddr}; -#[cfg(any(target_os = "illumos", target_os = "solaris"))] -#[allow(deprecated)] -pub use self::addr::{AddressFamily, SockAddr, UnixAddr}; -#[allow(deprecated)] -#[cfg(not(any( - target_os = "illumos", - target_os = "solaris", - target_os = "haiku" -)))] -#[cfg(feature = "net")] -pub use self::addr::{ - InetAddr, IpAddr, Ipv4Addr, Ipv6Addr, LinkAddr, SockaddrIn, SockaddrIn6, -}; -#[allow(deprecated)] -#[cfg(any( - target_os = "illumos", - target_os = "solaris", - target_os = "haiku" -))] -#[cfg(feature = "net")] -pub use self::addr::{ - InetAddr, IpAddr, Ipv4Addr, Ipv6Addr, SockaddrIn, SockaddrIn6, -}; - -#[cfg(any(target_os = "android", target_os = "linux"))] -pub use crate::sys::socket::addr::alg::AlgAddr; -#[cfg(any(target_os = "android", target_os = "linux"))] -pub use crate::sys::socket::addr::netlink::NetlinkAddr; -#[cfg(any(target_os = "ios", target_os = "macos"))] -#[cfg(feature = "ioctl")] -pub use crate::sys::socket::addr::sys_control::SysControlAddr; -#[cfg(any(target_os = "android", target_os = "linux"))] -pub use crate::sys::socket::addr::vsock::VsockAddr; - -#[cfg(feature = "uio")] -pub use libc::{cmsghdr, msghdr}; -pub use libc::{sa_family_t, sockaddr, sockaddr_storage, sockaddr_un}; -#[cfg(feature = "net")] -pub use libc::{sockaddr_in, sockaddr_in6}; - -// Needed by the cmsg_space macro -#[doc(hidden)] -pub use libc::{c_uint, CMSG_SPACE}; - -#[cfg(feature = "net")] -use crate::sys::socket::addr::{ipv4addr_to_libc, ipv6addr_to_libc}; - -/// These constants are used to specify the communication semantics -/// when creating a socket with [`socket()`](fn.socket.html) -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -#[repr(i32)] -#[non_exhaustive] -pub enum SockType { - /// Provides sequenced, reliable, two-way, connection- - /// based byte streams. An out-of-band data transmission - /// mechanism may be supported. - Stream = libc::SOCK_STREAM, - /// Supports datagrams (connectionless, unreliable - /// messages of a fixed maximum length). - Datagram = libc::SOCK_DGRAM, - /// Provides a sequenced, reliable, two-way connection- - /// based data transmission path for datagrams of fixed - /// maximum length; a consumer is required to read an - /// entire packet with each input system call. - SeqPacket = libc::SOCK_SEQPACKET, - /// Provides raw network protocol access. - Raw = libc::SOCK_RAW, - /// Provides a reliable datagram layer that does not - /// guarantee ordering. - #[cfg(not(any(target_os = "haiku")))] - Rdm = libc::SOCK_RDM, -} -// The TryFrom impl could've been derived using libc_enum!. But for -// backwards-compatibility with Nix-0.25.0 we manually implement it, so as to -// keep the old variant names. -impl TryFrom<i32> for SockType { - type Error = crate::Error; - - fn try_from(x: i32) -> Result<Self> { - match x { - libc::SOCK_STREAM => Ok(Self::Stream), - libc::SOCK_DGRAM => Ok(Self::Datagram), - libc::SOCK_SEQPACKET => Ok(Self::SeqPacket), - libc::SOCK_RAW => Ok(Self::Raw), - #[cfg(not(any(target_os = "haiku")))] - libc::SOCK_RDM => Ok(Self::Rdm), - _ => Err(Errno::EINVAL) - } - } -} - -/// Constants used in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html) -/// to specify the protocol to use. -#[repr(i32)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -#[non_exhaustive] -pub enum SockProtocol { - /// TCP protocol ([ip(7)](https://man7.org/linux/man-pages/man7/ip.7.html)) - Tcp = libc::IPPROTO_TCP, - /// UDP protocol ([ip(7)](https://man7.org/linux/man-pages/man7/ip.7.html)) - Udp = libc::IPPROTO_UDP, - /// Raw sockets ([raw(7)](https://man7.org/linux/man-pages/man7/raw.7.html)) - Raw = libc::IPPROTO_RAW, - /// Allows applications and other KEXTs to be notified when certain kernel events occur - /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html)) - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - KextEvent = libc::SYSPROTO_EVENT, - /// Allows applications to configure and control a KEXT - /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html)) - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - KextControl = libc::SYSPROTO_CONTROL, - /// Receives routing and link updates and may be used to modify the routing tables (both IPv4 and IPv6), IP addresses, link - // parameters, neighbor setups, queueing disciplines, traffic classes and packet classifiers - /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NetlinkRoute = libc::NETLINK_ROUTE, - /// Reserved for user-mode socket protocols - /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NetlinkUserSock = libc::NETLINK_USERSOCK, - /// Query information about sockets of various protocol families from the kernel - /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NetlinkSockDiag = libc::NETLINK_SOCK_DIAG, - /// SELinux event notifications. - /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NetlinkSELinux = libc::NETLINK_SELINUX, - /// Open-iSCSI - /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NetlinkISCSI = libc::NETLINK_ISCSI, - /// Auditing - /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NetlinkAudit = libc::NETLINK_AUDIT, - /// Access to FIB lookup from user space - /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NetlinkFIBLookup = libc::NETLINK_FIB_LOOKUP, - /// Netfilter subsystem - /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NetlinkNetFilter = libc::NETLINK_NETFILTER, - /// SCSI Transports - /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NetlinkSCSITransport = libc::NETLINK_SCSITRANSPORT, - /// Infiniband RDMA - /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NetlinkRDMA = libc::NETLINK_RDMA, - /// Transport IPv6 packets from netfilter to user space. Used by ip6_queue kernel module. - /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NetlinkIPv6Firewall = libc::NETLINK_IP6_FW, - /// DECnet routing messages - /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NetlinkDECNetRoutingMessage = libc::NETLINK_DNRTMSG, - /// Kernel messages to user space - /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NetlinkKObjectUEvent = libc::NETLINK_KOBJECT_UEVENT, - /// Netlink interface to request information about ciphers registered with the kernel crypto API as well as allow - /// configuration of the kernel crypto API. - /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NetlinkCrypto = libc::NETLINK_CRYPTO, - /// Non-DIX type protocol number defined for the Ethernet IEEE 802.3 interface that allows packets of all protocols - /// defined in the interface to be received. - /// ([ref](https://man7.org/linux/man-pages/man7/packet.7.html)) - // The protocol number is fed into the socket syscall in network byte order. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - EthAll = libc::ETH_P_ALL.to_be(), -} - -#[cfg(any(target_os = "linux"))] -libc_bitflags! { - /// Configuration flags for `SO_TIMESTAMPING` interface - /// - /// For use with [`Timestamping`][sockopt::Timestamping]. - /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) - pub struct TimestampingFlag: c_uint { - /// Report any software timestamps when available. - SOF_TIMESTAMPING_SOFTWARE; - /// Report hardware timestamps as generated by SOF_TIMESTAMPING_TX_HARDWARE when available. - SOF_TIMESTAMPING_RAW_HARDWARE; - /// Collect transmiting timestamps as reported by hardware - SOF_TIMESTAMPING_TX_HARDWARE; - /// Collect transmiting timestamps as reported by software - SOF_TIMESTAMPING_TX_SOFTWARE; - /// Collect receiving timestamps as reported by hardware - SOF_TIMESTAMPING_RX_HARDWARE; - /// Collect receiving timestamps as reported by software - SOF_TIMESTAMPING_RX_SOFTWARE; - } -} - -libc_bitflags! { - /// Additional socket options - pub struct SockFlag: c_int { - /// Set non-blocking mode on the new socket - #[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - SOCK_NONBLOCK; - /// Set close-on-exec on the new descriptor - #[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - SOCK_CLOEXEC; - /// Return `EPIPE` instead of raising `SIGPIPE` - #[cfg(target_os = "netbsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - SOCK_NOSIGPIPE; - /// For domains `AF_INET(6)`, only allow `connect(2)`, `sendto(2)`, or `sendmsg(2)` - /// to the DNS port (typically 53) - #[cfg(target_os = "openbsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - SOCK_DNS; - } -} - -libc_bitflags! { - /// Flags for send/recv and their relatives - pub struct MsgFlags: c_int { - /// Sends or requests out-of-band data on sockets that support this notion - /// (e.g., of type [`Stream`](enum.SockType.html)); the underlying protocol must also - /// support out-of-band data. - #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 - MSG_OOB; - /// Peeks at an incoming message. The data is treated as unread and the next - /// [`recv()`](fn.recv.html) - /// or similar function shall still return this data. - #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 - MSG_PEEK; - /// Receive operation blocks until the full amount of data can be - /// returned. The function may return smaller amount of data if a signal - /// is caught, an error or disconnect occurs. - #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 - MSG_WAITALL; - /// Enables nonblocking operation; if the operation would block, - /// `EAGAIN` or `EWOULDBLOCK` is returned. This provides similar - /// behavior to setting the `O_NONBLOCK` flag - /// (via the [`fcntl`](../../fcntl/fn.fcntl.html) - /// `F_SETFL` operation), but differs in that `MSG_DONTWAIT` is a per- - /// call option, whereas `O_NONBLOCK` is a setting on the open file - /// description (see [open(2)](https://man7.org/linux/man-pages/man2/open.2.html)), - /// which will affect all threads in - /// the calling process and as well as other processes that hold - /// file descriptors referring to the same open file description. - #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 - MSG_DONTWAIT; - /// Receive flags: Control Data was discarded (buffer too small) - #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 - MSG_CTRUNC; - /// For raw ([`Packet`](addr/enum.AddressFamily.html)), Internet datagram - /// (since Linux 2.4.27/2.6.8), - /// netlink (since Linux 2.6.22) and UNIX datagram (since Linux 3.4) - /// sockets: return the real length of the packet or datagram, even - /// when it was longer than the passed buffer. Not implemented for UNIX - /// domain ([unix(7)](https://linux.die.net/man/7/unix)) sockets. - /// - /// For use with Internet stream sockets, see [tcp(7)](https://linux.die.net/man/7/tcp). - #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 - MSG_TRUNC; - /// Terminates a record (when this notion is supported, as for - /// sockets of type [`SeqPacket`](enum.SockType.html)). - #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 - MSG_EOR; - /// This flag specifies that queued errors should be received from - /// the socket error queue. (For more details, see - /// [recvfrom(2)](https://linux.die.net/man/2/recvfrom)) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 - MSG_ERRQUEUE; - /// Set the `close-on-exec` flag for the file descriptor received via a UNIX domain - /// file descriptor using the `SCM_RIGHTS` operation (described in - /// [unix(7)](https://linux.die.net/man/7/unix)). - /// This flag is useful for the same reasons as the `O_CLOEXEC` flag of - /// [open(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html). - /// - /// Only used in [`recvmsg`](fn.recvmsg.html) function. - #[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 - MSG_CMSG_CLOEXEC; - /// Requests not to send `SIGPIPE` errors when the other end breaks the connection. - /// (For more details, see [send(2)](https://linux.die.net/man/2/send)). - #[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 - MSG_NOSIGNAL; - } -} - -cfg_if! { - if #[cfg(any(target_os = "android", target_os = "linux"))] { - /// Unix credentials of the sending process. - /// - /// This struct is used with the `SO_PEERCRED` ancillary message - /// and the `SCM_CREDENTIALS` control message for UNIX sockets. - #[repr(transparent)] - #[derive(Clone, Copy, Debug, Eq, PartialEq)] - pub struct UnixCredentials(libc::ucred); - - impl UnixCredentials { - /// Creates a new instance with the credentials of the current process - pub fn new() -> Self { - // Safe because these FFI functions are inherently safe - unsafe { - UnixCredentials(libc::ucred { - pid: libc::getpid(), - uid: libc::getuid(), - gid: libc::getgid() - }) - } - } - - /// Returns the process identifier - pub fn pid(&self) -> libc::pid_t { - self.0.pid - } - - /// Returns the user identifier - pub fn uid(&self) -> libc::uid_t { - self.0.uid - } - - /// Returns the group identifier - pub fn gid(&self) -> libc::gid_t { - self.0.gid - } - } - - impl Default for UnixCredentials { - fn default() -> Self { - Self::new() - } - } - - impl From<libc::ucred> for UnixCredentials { - fn from(cred: libc::ucred) -> Self { - UnixCredentials(cred) - } - } - - impl From<UnixCredentials> for libc::ucred { - fn from(uc: UnixCredentials) -> Self { - uc.0 - } - } - } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] { - /// Unix credentials of the sending process. - /// - /// This struct is used with the `SCM_CREDS` ancillary message for UNIX sockets. - #[repr(transparent)] - #[derive(Clone, Copy, Debug, Eq, PartialEq)] - pub struct UnixCredentials(libc::cmsgcred); - - impl UnixCredentials { - /// Returns the process identifier - pub fn pid(&self) -> libc::pid_t { - self.0.cmcred_pid - } - - /// Returns the real user identifier - pub fn uid(&self) -> libc::uid_t { - self.0.cmcred_uid - } - - /// Returns the effective user identifier - pub fn euid(&self) -> libc::uid_t { - self.0.cmcred_euid - } - - /// Returns the real group identifier - pub fn gid(&self) -> libc::gid_t { - self.0.cmcred_gid - } - - /// Returns a list group identifiers (the first one being the effective GID) - pub fn groups(&self) -> &[libc::gid_t] { - unsafe { - slice::from_raw_parts( - self.0.cmcred_groups.as_ptr() as *const libc::gid_t, - self.0.cmcred_ngroups as _ - ) - } - } - } - - impl From<libc::cmsgcred> for UnixCredentials { - fn from(cred: libc::cmsgcred) -> Self { - UnixCredentials(cred) - } - } - } -} - -cfg_if! { - if #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "ios" - ))] { - /// Return type of [`LocalPeerCred`](crate::sys::socket::sockopt::LocalPeerCred) - #[repr(transparent)] - #[derive(Clone, Copy, Debug, Eq, PartialEq)] - pub struct XuCred(libc::xucred); - - impl XuCred { - /// Structure layout version - pub fn version(&self) -> u32 { - self.0.cr_version - } - - /// Effective user ID - pub fn uid(&self) -> libc::uid_t { - self.0.cr_uid - } - - /// Returns a list of group identifiers (the first one being the - /// effective GID) - pub fn groups(&self) -> &[libc::gid_t] { - &self.0.cr_groups - } - } - } -} - -feature! { -#![feature = "net"] -/// Request for multicast socket operations -/// -/// This is a wrapper type around `ip_mreq`. -#[repr(transparent)] -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct IpMembershipRequest(libc::ip_mreq); - -impl IpMembershipRequest { - /// Instantiate a new `IpMembershipRequest` - /// - /// If `interface` is `None`, then `Ipv4Addr::any()` will be used for the interface. - pub fn new(group: net::Ipv4Addr, interface: Option<net::Ipv4Addr>) - -> Self - { - let imr_addr = match interface { - None => net::Ipv4Addr::UNSPECIFIED, - Some(addr) => addr - }; - IpMembershipRequest(libc::ip_mreq { - imr_multiaddr: ipv4addr_to_libc(group), - imr_interface: ipv4addr_to_libc(imr_addr) - }) - } -} - -/// Request for ipv6 multicast socket operations -/// -/// This is a wrapper type around `ipv6_mreq`. -#[repr(transparent)] -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct Ipv6MembershipRequest(libc::ipv6_mreq); - -impl Ipv6MembershipRequest { - /// Instantiate a new `Ipv6MembershipRequest` - pub const fn new(group: net::Ipv6Addr) -> Self { - Ipv6MembershipRequest(libc::ipv6_mreq { - ipv6mr_multiaddr: ipv6addr_to_libc(&group), - ipv6mr_interface: 0, - }) - } -} -} - -feature! { -#![feature = "uio"] - -/// Create a buffer large enough for storing some control messages as returned -/// by [`recvmsg`](fn.recvmsg.html). -/// -/// # Examples -/// -/// ``` -/// # #[macro_use] extern crate nix; -/// # use nix::sys::time::TimeVal; -/// # use std::os::unix::io::RawFd; -/// # fn main() { -/// // Create a buffer for a `ControlMessageOwned::ScmTimestamp` message -/// let _ = cmsg_space!(TimeVal); -/// // Create a buffer big enough for a `ControlMessageOwned::ScmRights` message -/// // with two file descriptors -/// let _ = cmsg_space!([RawFd; 2]); -/// // Create a buffer big enough for a `ControlMessageOwned::ScmRights` message -/// // and a `ControlMessageOwned::ScmTimestamp` message -/// let _ = cmsg_space!(RawFd, TimeVal); -/// # } -/// ``` -// Unfortunately, CMSG_SPACE isn't a const_fn, or else we could return a -// stack-allocated array. -#[macro_export] -macro_rules! cmsg_space { - ( $( $x:ty ),* ) => { - { - let mut space = 0; - $( - // CMSG_SPACE is always safe - space += unsafe { - $crate::sys::socket::CMSG_SPACE(::std::mem::size_of::<$x>() as $crate::sys::socket::c_uint) - } as usize; - )* - Vec::<u8>::with_capacity(space) - } - } -} - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -/// Contains outcome of sending or receiving a message -/// -/// Use [`cmsgs`][RecvMsg::cmsgs] to access all the control messages present, and -/// [`iovs`][RecvMsg::iovs`] to access underlying io slices. -pub struct RecvMsg<'a, 's, S> { - pub bytes: usize, - cmsghdr: Option<&'a cmsghdr>, - pub address: Option<S>, - pub flags: MsgFlags, - iobufs: std::marker::PhantomData<& 's()>, - mhdr: msghdr, -} - -impl<'a, S> RecvMsg<'a, '_, S> { - /// Iterate over the valid control messages pointed to by this - /// msghdr. - pub fn cmsgs(&self) -> CmsgIterator { - CmsgIterator { - cmsghdr: self.cmsghdr, - mhdr: &self.mhdr - } - } -} - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct CmsgIterator<'a> { - /// Control message buffer to decode from. Must adhere to cmsg alignment. - cmsghdr: Option<&'a cmsghdr>, - mhdr: &'a msghdr -} - -impl<'a> Iterator for CmsgIterator<'a> { - type Item = ControlMessageOwned; - - fn next(&mut self) -> Option<ControlMessageOwned> { - match self.cmsghdr { - None => None, // No more messages - Some(hdr) => { - // Get the data. - // Safe if cmsghdr points to valid data returned by recvmsg(2) - let cm = unsafe { Some(ControlMessageOwned::decode_from(hdr))}; - // Advance the internal pointer. Safe if mhdr and cmsghdr point - // to valid data returned by recvmsg(2) - self.cmsghdr = unsafe { - let p = CMSG_NXTHDR(self.mhdr as *const _, hdr as *const _); - p.as_ref() - }; - cm - } - } - } -} - -/// A type-safe wrapper around a single control message, as used with -/// [`recvmsg`](#fn.recvmsg). -/// -/// [Further reading](https://man7.org/linux/man-pages/man3/cmsg.3.html) -// Nix version 0.13.0 and earlier used ControlMessage for both recvmsg and -// sendmsg. However, on some platforms the messages returned by recvmsg may be -// unaligned. ControlMessageOwned takes those messages by copy, obviating any -// alignment issues. -// -// See https://github.com/nix-rust/nix/issues/999 -#[derive(Clone, Debug, Eq, PartialEq)] -#[non_exhaustive] -pub enum ControlMessageOwned { - /// Received version of [`ControlMessage::ScmRights`] - ScmRights(Vec<RawFd>), - /// Received version of [`ControlMessage::ScmCredentials`] - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ScmCredentials(UnixCredentials), - /// Received version of [`ControlMessage::ScmCreds`] - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ScmCreds(UnixCredentials), - /// A message of type `SCM_TIMESTAMP`, containing the time the - /// packet was received by the kernel. - /// - /// See the kernel's explanation in "SO_TIMESTAMP" of - /// [networking/timestamping](https://www.kernel.org/doc/Documentation/networking/timestamping.txt). - /// - /// # Examples - /// - /// ``` - /// # #[macro_use] extern crate nix; - /// # use nix::sys::socket::*; - /// # use nix::sys::time::*; - /// # use std::io::{IoSlice, IoSliceMut}; - /// # use std::time::*; - /// # use std::str::FromStr; - /// # fn main() { - /// // Set up - /// let message = "Ohayō!".as_bytes(); - /// let in_socket = socket( - /// AddressFamily::Inet, - /// SockType::Datagram, - /// SockFlag::empty(), - /// None).unwrap(); - /// setsockopt(in_socket, sockopt::ReceiveTimestamp, &true).unwrap(); - /// let localhost = SockaddrIn::from_str("127.0.0.1:0").unwrap(); - /// bind(in_socket, &localhost).unwrap(); - /// let address: SockaddrIn = getsockname(in_socket).unwrap(); - /// // Get initial time - /// let time0 = SystemTime::now(); - /// // Send the message - /// let iov = [IoSlice::new(message)]; - /// let flags = MsgFlags::empty(); - /// let l = sendmsg(in_socket, &iov, &[], flags, Some(&address)).unwrap(); - /// assert_eq!(message.len(), l); - /// // Receive the message - /// let mut buffer = vec![0u8; message.len()]; - /// let mut cmsgspace = cmsg_space!(TimeVal); - /// let mut iov = [IoSliceMut::new(&mut buffer)]; - /// let r = recvmsg::<SockaddrIn>(in_socket, &mut iov, Some(&mut cmsgspace), flags) - /// .unwrap(); - /// let rtime = match r.cmsgs().next() { - /// Some(ControlMessageOwned::ScmTimestamp(rtime)) => rtime, - /// Some(_) => panic!("Unexpected control message"), - /// None => panic!("No control message") - /// }; - /// // Check the final time - /// let time1 = SystemTime::now(); - /// // the packet's received timestamp should lie in-between the two system - /// // times, unless the system clock was adjusted in the meantime. - /// let rduration = Duration::new(rtime.tv_sec() as u64, - /// rtime.tv_usec() as u32 * 1000); - /// assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration); - /// assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap()); - /// // Close socket - /// nix::unistd::close(in_socket).unwrap(); - /// # } - /// ``` - ScmTimestamp(TimeVal), - /// A set of nanosecond resolution timestamps - /// - /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) - #[cfg(all(target_os = "linux"))] - ScmTimestampsns(Timestamps), - /// Nanoseconds resolution timestamp - /// - /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) - #[cfg(all(target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ScmTimestampns(TimeSpec), - #[cfg(any( - target_os = "android", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - ))] - #[cfg(feature = "net")] - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - Ipv4PacketInfo(libc::in_pktinfo), - #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "openbsd", - target_os = "netbsd", - ))] - #[cfg(feature = "net")] - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - Ipv6PacketInfo(libc::in6_pktinfo), - #[cfg(any( - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - ))] - #[cfg(feature = "net")] - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - Ipv4RecvIf(libc::sockaddr_dl), - #[cfg(any( - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - ))] - #[cfg(feature = "net")] - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - Ipv4RecvDstAddr(libc::in_addr), - #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] - #[cfg(feature = "net")] - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - Ipv4OrigDstAddr(libc::sockaddr_in), - #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] - #[cfg(feature = "net")] - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - Ipv6OrigDstAddr(libc::sockaddr_in6), - - /// UDP Generic Receive Offload (GRO) allows receiving multiple UDP - /// packets from a single sender. - /// Fixed-size payloads are following one by one in a receive buffer. - /// This Control Message indicates the size of all smaller packets, - /// except, maybe, the last one. - /// - /// `UdpGroSegment` socket option should be enabled on a socket - /// to allow receiving GRO packets. - #[cfg(target_os = "linux")] - #[cfg(feature = "net")] - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - UdpGroSegments(u16), - - /// SO_RXQ_OVFL indicates that an unsigned 32 bit value - /// ancilliary msg (cmsg) should be attached to recieved - /// skbs indicating the number of packets dropped by the - /// socket between the last recieved packet and this - /// received packet. - /// - /// `RxqOvfl` socket option should be enabled on a socket - /// to allow receiving the drop counter. - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - RxqOvfl(u32), - - /// Socket error queue control messages read with the `MSG_ERRQUEUE` flag. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg(feature = "net")] - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - Ipv4RecvErr(libc::sock_extended_err, Option<sockaddr_in>), - /// Socket error queue control messages read with the `MSG_ERRQUEUE` flag. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg(feature = "net")] - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - Ipv6RecvErr(libc::sock_extended_err, Option<sockaddr_in6>), - - /// Catch-all variant for unimplemented cmsg types. - #[doc(hidden)] - Unknown(UnknownCmsg), -} - -/// For representing packet timestamps via `SO_TIMESTAMPING` interface -#[cfg(all(target_os = "linux"))] -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Timestamps { - /// software based timestamp, usually one containing data - pub system: TimeSpec, - /// legacy timestamp, usually empty - pub hw_trans: TimeSpec, - /// hardware based timestamp - pub hw_raw: TimeSpec, -} - -impl ControlMessageOwned { - /// Decodes a `ControlMessageOwned` from raw bytes. - /// - /// This is only safe to call if the data is correct for the message type - /// specified in the header. Normally, the kernel ensures that this is the - /// case. "Correct" in this case includes correct length, alignment and - /// actual content. - // Clippy complains about the pointer alignment of `p`, not understanding - // that it's being fed to a function that can handle that. - #[allow(clippy::cast_ptr_alignment)] - unsafe fn decode_from(header: &cmsghdr) -> ControlMessageOwned - { - let p = CMSG_DATA(header); - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - let len = header as *const _ as usize + header.cmsg_len as usize - - p as usize; - match (header.cmsg_level, header.cmsg_type) { - (libc::SOL_SOCKET, libc::SCM_RIGHTS) => { - let n = len / mem::size_of::<RawFd>(); - let mut fds = Vec::with_capacity(n); - for i in 0..n { - let fdp = (p as *const RawFd).add(i); - fds.push(ptr::read_unaligned(fdp)); - } - ControlMessageOwned::ScmRights(fds) - }, - #[cfg(any(target_os = "android", target_os = "linux"))] - (libc::SOL_SOCKET, libc::SCM_CREDENTIALS) => { - let cred: libc::ucred = ptr::read_unaligned(p as *const _); - ControlMessageOwned::ScmCredentials(cred.into()) - } - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - (libc::SOL_SOCKET, libc::SCM_CREDS) => { - let cred: libc::cmsgcred = ptr::read_unaligned(p as *const _); - ControlMessageOwned::ScmCreds(cred.into()) - } - #[cfg(not(target_os = "haiku"))] - (libc::SOL_SOCKET, libc::SCM_TIMESTAMP) => { - let tv: libc::timeval = ptr::read_unaligned(p as *const _); - ControlMessageOwned::ScmTimestamp(TimeVal::from(tv)) - }, - #[cfg(all(target_os = "linux"))] - (libc::SOL_SOCKET, libc::SCM_TIMESTAMPNS) => { - let ts: libc::timespec = ptr::read_unaligned(p as *const _); - ControlMessageOwned::ScmTimestampns(TimeSpec::from(ts)) - } - #[cfg(all(target_os = "linux"))] - (libc::SOL_SOCKET, libc::SCM_TIMESTAMPING) => { - let tp = p as *const libc::timespec; - let ts: libc::timespec = ptr::read_unaligned(tp); - let system = TimeSpec::from(ts); - let ts: libc::timespec = ptr::read_unaligned(tp.add(1)); - let hw_trans = TimeSpec::from(ts); - let ts: libc::timespec = ptr::read_unaligned(tp.add(2)); - let hw_raw = TimeSpec::from(ts); - let timestamping = Timestamps { system, hw_trans, hw_raw }; - ControlMessageOwned::ScmTimestampsns(timestamping) - } - #[cfg(any( - target_os = "android", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos" - ))] - #[cfg(feature = "net")] - (libc::IPPROTO_IPV6, libc::IPV6_PKTINFO) => { - let info = ptr::read_unaligned(p as *const libc::in6_pktinfo); - ControlMessageOwned::Ipv6PacketInfo(info) - } - #[cfg(any( - target_os = "android", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - ))] - #[cfg(feature = "net")] - (libc::IPPROTO_IP, libc::IP_PKTINFO) => { - let info = ptr::read_unaligned(p as *const libc::in_pktinfo); - ControlMessageOwned::Ipv4PacketInfo(info) - } - #[cfg(any( - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - ))] - #[cfg(feature = "net")] - (libc::IPPROTO_IP, libc::IP_RECVIF) => { - let dl = ptr::read_unaligned(p as *const libc::sockaddr_dl); - ControlMessageOwned::Ipv4RecvIf(dl) - }, - #[cfg(any( - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - ))] - #[cfg(feature = "net")] - (libc::IPPROTO_IP, libc::IP_RECVDSTADDR) => { - let dl = ptr::read_unaligned(p as *const libc::in_addr); - ControlMessageOwned::Ipv4RecvDstAddr(dl) - }, - #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] - #[cfg(feature = "net")] - (libc::IPPROTO_IP, libc::IP_ORIGDSTADDR) => { - let dl = ptr::read_unaligned(p as *const libc::sockaddr_in); - ControlMessageOwned::Ipv4OrigDstAddr(dl) - }, - #[cfg(target_os = "linux")] - #[cfg(feature = "net")] - (libc::SOL_UDP, libc::UDP_GRO) => { - let gso_size: u16 = ptr::read_unaligned(p as *const _); - ControlMessageOwned::UdpGroSegments(gso_size) - }, - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - (libc::SOL_SOCKET, libc::SO_RXQ_OVFL) => { - let drop_counter = ptr::read_unaligned(p as *const u32); - ControlMessageOwned::RxqOvfl(drop_counter) - }, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg(feature = "net")] - (libc::IPPROTO_IP, libc::IP_RECVERR) => { - let (err, addr) = Self::recv_err_helper::<sockaddr_in>(p, len); - ControlMessageOwned::Ipv4RecvErr(err, addr) - }, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg(feature = "net")] - (libc::IPPROTO_IPV6, libc::IPV6_RECVERR) => { - let (err, addr) = Self::recv_err_helper::<sockaddr_in6>(p, len); - ControlMessageOwned::Ipv6RecvErr(err, addr) - }, - #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] - #[cfg(feature = "net")] - (libc::IPPROTO_IPV6, libc::IPV6_ORIGDSTADDR) => { - let dl = ptr::read_unaligned(p as *const libc::sockaddr_in6); - ControlMessageOwned::Ipv6OrigDstAddr(dl) - }, - (_, _) => { - let sl = slice::from_raw_parts(p, len); - let ucmsg = UnknownCmsg(*header, Vec::<u8>::from(sl)); - ControlMessageOwned::Unknown(ucmsg) - } - } - } - - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg(feature = "net")] - #[allow(clippy::cast_ptr_alignment)] // False positive - unsafe fn recv_err_helper<T>(p: *mut libc::c_uchar, len: usize) -> (libc::sock_extended_err, Option<T>) { - let ee = p as *const libc::sock_extended_err; - let err = ptr::read_unaligned(ee); - - // For errors originating on the network, SO_EE_OFFENDER(ee) points inside the p[..len] - // CMSG_DATA buffer. For local errors, there is no address included in the control - // message, and SO_EE_OFFENDER(ee) points beyond the end of the buffer. So, we need to - // validate that the address object is in-bounds before we attempt to copy it. - let addrp = libc::SO_EE_OFFENDER(ee) as *const T; - - if addrp.offset(1) as usize - (p as usize) > len { - (err, None) - } else { - (err, Some(ptr::read_unaligned(addrp))) - } - } -} - -/// A type-safe zero-copy wrapper around a single control message, as used wih -/// [`sendmsg`](#fn.sendmsg). More types may be added to this enum; do not -/// exhaustively pattern-match it. -/// -/// [Further reading](https://man7.org/linux/man-pages/man3/cmsg.3.html) -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -#[non_exhaustive] -pub enum ControlMessage<'a> { - /// A message of type `SCM_RIGHTS`, containing an array of file - /// descriptors passed between processes. - /// - /// See the description in the "Ancillary messages" section of the - /// [unix(7) man page](https://man7.org/linux/man-pages/man7/unix.7.html). - /// - /// Using multiple `ScmRights` messages for a single `sendmsg` call isn't - /// recommended since it causes platform-dependent behaviour: It might - /// swallow all but the first `ScmRights` message or fail with `EINVAL`. - /// Instead, you can put all fds to be passed into a single `ScmRights` - /// message. - ScmRights(&'a [RawFd]), - /// A message of type `SCM_CREDENTIALS`, containing the pid, uid and gid of - /// a process connected to the socket. - /// - /// This is similar to the socket option `SO_PEERCRED`, but requires a - /// process to explicitly send its credentials. A process running as root is - /// allowed to specify any credentials, while credentials sent by other - /// processes are verified by the kernel. - /// - /// For further information, please refer to the - /// [`unix(7)`](https://man7.org/linux/man-pages/man7/unix.7.html) man page. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ScmCredentials(&'a UnixCredentials), - /// A message of type `SCM_CREDS`, containing the pid, uid, euid, gid and groups of - /// a process connected to the socket. - /// - /// This is similar to the socket options `LOCAL_CREDS` and `LOCAL_PEERCRED`, but - /// requires a process to explicitly send its credentials. - /// - /// Credentials are always overwritten by the kernel, so this variant does have - /// any data, unlike the receive-side - /// [`ControlMessageOwned::ScmCreds`]. - /// - /// For further information, please refer to the - /// [`unix(4)`](https://www.freebsd.org/cgi/man.cgi?query=unix) man page. - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ScmCreds, - - /// Set IV for `AF_ALG` crypto API. - /// - /// For further information, please refer to the - /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html) - #[cfg(any( - target_os = "android", - target_os = "linux", - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - AlgSetIv(&'a [u8]), - /// Set crypto operation for `AF_ALG` crypto API. It may be one of - /// `ALG_OP_ENCRYPT` or `ALG_OP_DECRYPT` - /// - /// For further information, please refer to the - /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html) - #[cfg(any( - target_os = "android", - target_os = "linux", - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - AlgSetOp(&'a libc::c_int), - /// Set the length of associated authentication data (AAD) (applicable only to AEAD algorithms) - /// for `AF_ALG` crypto API. - /// - /// For further information, please refer to the - /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html) - #[cfg(any( - target_os = "android", - target_os = "linux", - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - AlgSetAeadAssoclen(&'a u32), - - /// UDP GSO makes it possible for applications to generate network packets - /// for a virtual MTU much greater than the real one. - /// The length of the send data no longer matches the expected length on - /// the wire. - /// The size of the datagram payload as it should appear on the wire may be - /// passed through this control message. - /// Send buffer should consist of multiple fixed-size wire payloads - /// following one by one, and the last, possibly smaller one. - #[cfg(target_os = "linux")] - #[cfg(feature = "net")] - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - UdpGsoSegments(&'a u16), - - /// Configure the sending addressing and interface for v4 - /// - /// For further information, please refer to the - /// [`ip(7)`](https://man7.org/linux/man-pages/man7/ip.7.html) man page. - #[cfg(any(target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "android", - target_os = "ios",))] - #[cfg(feature = "net")] - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - Ipv4PacketInfo(&'a libc::in_pktinfo), - - /// Configure the sending addressing and interface for v6 - /// - /// For further information, please refer to the - /// [`ipv6(7)`](https://man7.org/linux/man-pages/man7/ipv6.7.html) man page. - #[cfg(any(target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "freebsd", - target_os = "android", - target_os = "ios",))] - #[cfg(feature = "net")] - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - Ipv6PacketInfo(&'a libc::in6_pktinfo), - - /// Configure the IPv4 source address with `IP_SENDSRCADDR`. - #[cfg(any( - target_os = "netbsd", - target_os = "freebsd", - target_os = "openbsd", - target_os = "dragonfly", - ))] - #[cfg(feature = "net")] - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - Ipv4SendSrcAddr(&'a libc::in_addr), - - /// SO_RXQ_OVFL indicates that an unsigned 32 bit value - /// ancilliary msg (cmsg) should be attached to recieved - /// skbs indicating the number of packets dropped by the - /// socket between the last recieved packet and this - /// received packet. - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - RxqOvfl(&'a u32), - - /// Configure the transmission time of packets. - /// - /// For further information, please refer to the - /// [`tc-etf(8)`](https://man7.org/linux/man-pages/man8/tc-etf.8.html) man - /// page. - #[cfg(target_os = "linux")] - TxTime(&'a u64), -} - -// An opaque structure used to prevent cmsghdr from being a public type -#[doc(hidden)] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct UnknownCmsg(cmsghdr, Vec<u8>); - -impl<'a> ControlMessage<'a> { - /// The value of CMSG_SPACE on this message. - /// Safe because CMSG_SPACE is always safe - fn space(&self) -> usize { - unsafe{CMSG_SPACE(self.len() as libc::c_uint) as usize} - } - - /// The value of CMSG_LEN on this message. - /// Safe because CMSG_LEN is always safe - #[cfg(any(target_os = "android", - all(target_os = "linux", not(target_env = "musl"))))] - fn cmsg_len(&self) -> usize { - unsafe{CMSG_LEN(self.len() as libc::c_uint) as usize} - } - - #[cfg(not(any(target_os = "android", - all(target_os = "linux", not(target_env = "musl")))))] - fn cmsg_len(&self) -> libc::c_uint { - unsafe{CMSG_LEN(self.len() as libc::c_uint)} - } - - /// Return a reference to the payload data as a byte pointer - fn copy_to_cmsg_data(&self, cmsg_data: *mut u8) { - let data_ptr = match *self { - ControlMessage::ScmRights(fds) => { - fds as *const _ as *const u8 - }, - #[cfg(any(target_os = "android", target_os = "linux"))] - ControlMessage::ScmCredentials(creds) => { - &creds.0 as *const libc::ucred as *const u8 - } - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - ControlMessage::ScmCreds => { - // The kernel overwrites the data, we just zero it - // to make sure it's not uninitialized memory - unsafe { ptr::write_bytes(cmsg_data, 0, self.len()) }; - return - } - #[cfg(any(target_os = "android", target_os = "linux"))] - ControlMessage::AlgSetIv(iv) => { - #[allow(deprecated)] // https://github.com/rust-lang/libc/issues/1501 - let af_alg_iv = libc::af_alg_iv { - ivlen: iv.len() as u32, - iv: [0u8; 0], - }; - - let size = mem::size_of_val(&af_alg_iv); - - unsafe { - ptr::copy_nonoverlapping( - &af_alg_iv as *const _ as *const u8, - cmsg_data, - size, - ); - ptr::copy_nonoverlapping( - iv.as_ptr(), - cmsg_data.add(size), - iv.len() - ); - }; - - return - }, - #[cfg(any(target_os = "android", target_os = "linux"))] - ControlMessage::AlgSetOp(op) => { - op as *const _ as *const u8 - }, - #[cfg(any(target_os = "android", target_os = "linux"))] - ControlMessage::AlgSetAeadAssoclen(len) => { - len as *const _ as *const u8 - }, - #[cfg(target_os = "linux")] - #[cfg(feature = "net")] - ControlMessage::UdpGsoSegments(gso_size) => { - gso_size as *const _ as *const u8 - }, - #[cfg(any(target_os = "linux", target_os = "macos", - target_os = "netbsd", target_os = "android", - target_os = "ios",))] - #[cfg(feature = "net")] - ControlMessage::Ipv4PacketInfo(info) => info as *const _ as *const u8, - #[cfg(any(target_os = "linux", target_os = "macos", - target_os = "netbsd", target_os = "freebsd", - target_os = "android", target_os = "ios",))] - #[cfg(feature = "net")] - ControlMessage::Ipv6PacketInfo(info) => info as *const _ as *const u8, - #[cfg(any(target_os = "netbsd", target_os = "freebsd", - target_os = "openbsd", target_os = "dragonfly"))] - #[cfg(feature = "net")] - ControlMessage::Ipv4SendSrcAddr(addr) => addr as *const _ as *const u8, - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - ControlMessage::RxqOvfl(drop_count) => { - drop_count as *const _ as *const u8 - }, - #[cfg(target_os = "linux")] - ControlMessage::TxTime(tx_time) => { - tx_time as *const _ as *const u8 - }, - }; - unsafe { - ptr::copy_nonoverlapping( - data_ptr, - cmsg_data, - self.len() - ) - }; - } - - /// The size of the payload, excluding its cmsghdr - fn len(&self) -> usize { - match *self { - ControlMessage::ScmRights(fds) => { - mem::size_of_val(fds) - }, - #[cfg(any(target_os = "android", target_os = "linux"))] - ControlMessage::ScmCredentials(creds) => { - mem::size_of_val(creds) - } - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - ControlMessage::ScmCreds => { - mem::size_of::<libc::cmsgcred>() - } - #[cfg(any(target_os = "android", target_os = "linux"))] - ControlMessage::AlgSetIv(iv) => { - mem::size_of::<&[u8]>() + iv.len() - }, - #[cfg(any(target_os = "android", target_os = "linux"))] - ControlMessage::AlgSetOp(op) => { - mem::size_of_val(op) - }, - #[cfg(any(target_os = "android", target_os = "linux"))] - ControlMessage::AlgSetAeadAssoclen(len) => { - mem::size_of_val(len) - }, - #[cfg(target_os = "linux")] - #[cfg(feature = "net")] - ControlMessage::UdpGsoSegments(gso_size) => { - mem::size_of_val(gso_size) - }, - #[cfg(any(target_os = "linux", target_os = "macos", - target_os = "netbsd", target_os = "android", - target_os = "ios",))] - #[cfg(feature = "net")] - ControlMessage::Ipv4PacketInfo(info) => mem::size_of_val(info), - #[cfg(any(target_os = "linux", target_os = "macos", - target_os = "netbsd", target_os = "freebsd", - target_os = "android", target_os = "ios",))] - #[cfg(feature = "net")] - ControlMessage::Ipv6PacketInfo(info) => mem::size_of_val(info), - #[cfg(any(target_os = "netbsd", target_os = "freebsd", - target_os = "openbsd", target_os = "dragonfly"))] - #[cfg(feature = "net")] - ControlMessage::Ipv4SendSrcAddr(addr) => mem::size_of_val(addr), - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - ControlMessage::RxqOvfl(drop_count) => { - mem::size_of_val(drop_count) - }, - #[cfg(target_os = "linux")] - ControlMessage::TxTime(tx_time) => { - mem::size_of_val(tx_time) - }, - } - } - - /// Returns the value to put into the `cmsg_level` field of the header. - fn cmsg_level(&self) -> libc::c_int { - match *self { - ControlMessage::ScmRights(_) => libc::SOL_SOCKET, - #[cfg(any(target_os = "android", target_os = "linux"))] - ControlMessage::ScmCredentials(_) => libc::SOL_SOCKET, - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - ControlMessage::ScmCreds => libc::SOL_SOCKET, - #[cfg(any(target_os = "android", target_os = "linux"))] - ControlMessage::AlgSetIv(_) | ControlMessage::AlgSetOp(_) | - ControlMessage::AlgSetAeadAssoclen(_) => libc::SOL_ALG, - #[cfg(target_os = "linux")] - #[cfg(feature = "net")] - ControlMessage::UdpGsoSegments(_) => libc::SOL_UDP, - #[cfg(any(target_os = "linux", target_os = "macos", - target_os = "netbsd", target_os = "android", - target_os = "ios",))] - #[cfg(feature = "net")] - ControlMessage::Ipv4PacketInfo(_) => libc::IPPROTO_IP, - #[cfg(any(target_os = "linux", target_os = "macos", - target_os = "netbsd", target_os = "freebsd", - target_os = "android", target_os = "ios",))] - #[cfg(feature = "net")] - ControlMessage::Ipv6PacketInfo(_) => libc::IPPROTO_IPV6, - #[cfg(any(target_os = "netbsd", target_os = "freebsd", - target_os = "openbsd", target_os = "dragonfly"))] - #[cfg(feature = "net")] - ControlMessage::Ipv4SendSrcAddr(_) => libc::IPPROTO_IP, - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - ControlMessage::RxqOvfl(_) => libc::SOL_SOCKET, - #[cfg(target_os = "linux")] - ControlMessage::TxTime(_) => libc::SOL_SOCKET, - } - } - - /// Returns the value to put into the `cmsg_type` field of the header. - fn cmsg_type(&self) -> libc::c_int { - match *self { - ControlMessage::ScmRights(_) => libc::SCM_RIGHTS, - #[cfg(any(target_os = "android", target_os = "linux"))] - ControlMessage::ScmCredentials(_) => libc::SCM_CREDENTIALS, - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - ControlMessage::ScmCreds => libc::SCM_CREDS, - #[cfg(any(target_os = "android", target_os = "linux"))] - ControlMessage::AlgSetIv(_) => { - libc::ALG_SET_IV - }, - #[cfg(any(target_os = "android", target_os = "linux"))] - ControlMessage::AlgSetOp(_) => { - libc::ALG_SET_OP - }, - #[cfg(any(target_os = "android", target_os = "linux"))] - ControlMessage::AlgSetAeadAssoclen(_) => { - libc::ALG_SET_AEAD_ASSOCLEN - }, - #[cfg(target_os = "linux")] - #[cfg(feature = "net")] - ControlMessage::UdpGsoSegments(_) => { - libc::UDP_SEGMENT - }, - #[cfg(any(target_os = "linux", target_os = "macos", - target_os = "netbsd", target_os = "android", - target_os = "ios",))] - #[cfg(feature = "net")] - ControlMessage::Ipv4PacketInfo(_) => libc::IP_PKTINFO, - #[cfg(any(target_os = "linux", target_os = "macos", - target_os = "netbsd", target_os = "freebsd", - target_os = "android", target_os = "ios",))] - #[cfg(feature = "net")] - ControlMessage::Ipv6PacketInfo(_) => libc::IPV6_PKTINFO, - #[cfg(any(target_os = "netbsd", target_os = "freebsd", - target_os = "openbsd", target_os = "dragonfly"))] - #[cfg(feature = "net")] - ControlMessage::Ipv4SendSrcAddr(_) => libc::IP_SENDSRCADDR, - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - ControlMessage::RxqOvfl(_) => { - libc::SO_RXQ_OVFL - }, - #[cfg(target_os = "linux")] - ControlMessage::TxTime(_) => { - libc::SCM_TXTIME - }, - } - } - - // Unsafe: cmsg must point to a valid cmsghdr with enough space to - // encode self. - unsafe fn encode_into(&self, cmsg: *mut cmsghdr) { - (*cmsg).cmsg_level = self.cmsg_level(); - (*cmsg).cmsg_type = self.cmsg_type(); - (*cmsg).cmsg_len = self.cmsg_len(); - self.copy_to_cmsg_data(CMSG_DATA(cmsg)); - } -} - - -/// Send data in scatter-gather vectors to a socket, possibly accompanied -/// by ancillary data. Optionally direct the message at the given address, -/// as with sendto. -/// -/// Allocates if cmsgs is nonempty. -/// -/// # Examples -/// When not directing to any specific address, use `()` for the generic type -/// ``` -/// # use nix::sys::socket::*; -/// # use nix::unistd::pipe; -/// # use std::io::IoSlice; -/// let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None, -/// SockFlag::empty()) -/// .unwrap(); -/// let (r, w) = pipe().unwrap(); -/// -/// let iov = [IoSlice::new(b"hello")]; -/// let fds = [r]; -/// let cmsg = ControlMessage::ScmRights(&fds); -/// sendmsg::<()>(fd1, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(); -/// ``` -/// When directing to a specific address, the generic type will be inferred. -/// ``` -/// # use nix::sys::socket::*; -/// # use nix::unistd::pipe; -/// # use std::io::IoSlice; -/// # use std::str::FromStr; -/// let localhost = SockaddrIn::from_str("1.2.3.4:8080").unwrap(); -/// let fd = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), -/// None).unwrap(); -/// let (r, w) = pipe().unwrap(); -/// -/// let iov = [IoSlice::new(b"hello")]; -/// let fds = [r]; -/// let cmsg = ControlMessage::ScmRights(&fds); -/// sendmsg(fd, &iov, &[cmsg], MsgFlags::empty(), Some(&localhost)).unwrap(); -/// ``` -pub fn sendmsg<S>(fd: RawFd, iov: &[IoSlice<'_>], cmsgs: &[ControlMessage], - flags: MsgFlags, addr: Option<&S>) -> Result<usize> - where S: SockaddrLike -{ - let capacity = cmsgs.iter().map(|c| c.space()).sum(); - - // First size the buffer needed to hold the cmsgs. It must be zeroed, - // because subsequent code will not clear the padding bytes. - let mut cmsg_buffer = vec![0u8; capacity]; - - let mhdr = pack_mhdr_to_send(&mut cmsg_buffer[..], iov, cmsgs, addr); - - let ret = unsafe { libc::sendmsg(fd, &mhdr, flags.bits()) }; - - Errno::result(ret).map(|r| r as usize) -} - - -/// An extension of `sendmsg` that allows the caller to transmit multiple -/// messages on a socket using a single system call. This has performance -/// benefits for some applications. -/// -/// Allocations are performed for cmsgs and to build `msghdr` buffer -/// -/// # Arguments -/// -/// * `fd`: Socket file descriptor -/// * `data`: Struct that implements `IntoIterator` with `SendMmsgData` items -/// * `flags`: Optional flags passed directly to the operating system. -/// -/// # Returns -/// `Vec` with numbers of sent bytes on each sent message. -/// -/// # References -/// [`sendmsg`](fn.sendmsg.html) -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", -))] -pub fn sendmmsg<'a, XS, AS, C, I, S>( - fd: RawFd, - data: &'a mut MultiHeaders<S>, - slices: XS, - // one address per group of slices - addrs: AS, - // shared across all the messages - cmsgs: C, - flags: MsgFlags -) -> crate::Result<MultiResults<'a, S>> - where - XS: IntoIterator<Item = &'a I>, - AS: AsRef<[Option<S>]>, - I: AsRef<[IoSlice<'a>]> + 'a, - C: AsRef<[ControlMessage<'a>]> + 'a, - S: SockaddrLike + 'a -{ - - let mut count = 0; - - - for (i, ((slice, addr), mmsghdr)) in slices.into_iter().zip(addrs.as_ref()).zip(data.items.iter_mut() ).enumerate() { - let mut p = &mut mmsghdr.msg_hdr; - p.msg_iov = slice.as_ref().as_ptr() as *mut libc::iovec; - p.msg_iovlen = slice.as_ref().len() as _; - - p.msg_namelen = addr.as_ref().map_or(0, S::len); - p.msg_name = addr.as_ref().map_or(ptr::null(), S::as_ptr) as _; - - // Encode each cmsg. This must happen after initializing the header because - // CMSG_NEXT_HDR and friends read the msg_control and msg_controllen fields. - // CMSG_FIRSTHDR is always safe - let mut pmhdr: *mut cmsghdr = unsafe { CMSG_FIRSTHDR(p) }; - for cmsg in cmsgs.as_ref() { - assert_ne!(pmhdr, ptr::null_mut()); - // Safe because we know that pmhdr is valid, and we initialized it with - // sufficient space - unsafe { cmsg.encode_into(pmhdr) }; - // Safe because mhdr is valid - pmhdr = unsafe { CMSG_NXTHDR(p, pmhdr) }; - } - - count = i+1; - } - - let sent = Errno::result(unsafe { - libc::sendmmsg( - fd, - data.items.as_mut_ptr(), - count as _, - flags.bits() as _ - ) - })? as usize; - - Ok(MultiResults { - rmm: data, - current_index: 0, - received: sent - }) - -} - - -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", -))] -#[derive(Debug)] -/// Preallocated structures needed for [`recvmmsg`] and [`sendmmsg`] functions -pub struct MultiHeaders<S> { - // preallocated boxed slice of mmsghdr - items: Box<[libc::mmsghdr]>, - addresses: Box<[mem::MaybeUninit<S>]>, - // while we are not using it directly - this is used to store control messages - // and we retain pointers to them inside items array - #[allow(dead_code)] - cmsg_buffers: Option<Box<[u8]>>, - msg_controllen: usize, -} - -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", -))] -impl<S> MultiHeaders<S> { - /// Preallocate structure used by [`recvmmsg`] and [`sendmmsg`] takes number of headers to preallocate - /// - /// `cmsg_buffer` should be created with [`cmsg_space!`] if needed - pub fn preallocate(num_slices: usize, cmsg_buffer: Option<Vec<u8>>) -> Self - where - S: Copy + SockaddrLike, - { - // we will be storing pointers to addresses inside mhdr - convert it into boxed - // slice so it can'be changed later by pushing anything into self.addresses - let mut addresses = vec![std::mem::MaybeUninit::uninit(); num_slices].into_boxed_slice(); - - let msg_controllen = cmsg_buffer.as_ref().map_or(0, |v| v.capacity()); - - // we'll need a cmsg_buffer for each slice, we preallocate a vector and split - // it into "slices" parts - let cmsg_buffers = - cmsg_buffer.map(|v| vec![0u8; v.capacity() * num_slices].into_boxed_slice()); - - let items = addresses - .iter_mut() - .enumerate() - .map(|(ix, address)| { - let (ptr, cap) = match &cmsg_buffers { - Some(v) => ((&v[ix * msg_controllen] as *const u8), msg_controllen), - None => (std::ptr::null(), 0), - }; - let msg_hdr = unsafe { pack_mhdr_to_receive(std::ptr::null(), 0, ptr, cap, address.as_mut_ptr()) }; - libc::mmsghdr { - msg_hdr, - msg_len: 0, - } - }) - .collect::<Vec<_>>(); - - Self { - items: items.into_boxed_slice(), - addresses, - cmsg_buffers, - msg_controllen, - } - } -} - -/// An extension of recvmsg that allows the caller to receive multiple messages from a socket using a single system call. -/// -/// This has performance benefits for some applications. -/// -/// This method performs no allocations. -/// -/// Returns an iterator producing [`RecvMsg`], one per received messages. Each `RecvMsg` can produce -/// iterators over [`IoSlice`] with [`iovs`][RecvMsg::iovs`] and -/// `ControlMessageOwned` with [`cmsgs`][RecvMsg::cmsgs]. -/// -/// # Bugs (in underlying implementation, at least in Linux) -/// The timeout argument does not work as intended. The timeout is checked only after the receipt -/// of each datagram, so that if up to `vlen`-1 datagrams are received before the timeout expires, -/// but then no further datagrams are received, the call will block forever. -/// -/// If an error occurs after at least one message has been received, the call succeeds, and returns -/// the number of messages received. The error code is expected to be returned on a subsequent -/// call to recvmmsg(). In the current implementation, however, the error code can be -/// overwritten in the meantime by an unrelated network event on a socket, for example an -/// incoming ICMP packet. - -// On aarch64 linux using recvmmsg and trying to get hardware/kernel timestamps might not -// always produce the desired results - see https://github.com/nix-rust/nix/pull/1744 for more -// details - -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", -))] -pub fn recvmmsg<'a, XS, S, I>( - fd: RawFd, - data: &'a mut MultiHeaders<S>, - slices: XS, - flags: MsgFlags, - mut timeout: Option<crate::sys::time::TimeSpec>, -) -> crate::Result<MultiResults<'a, S>> -where - XS: IntoIterator<Item = &'a I>, - I: AsRef<[IoSliceMut<'a>]> + 'a, -{ - let mut count = 0; - for (i, (slice, mmsghdr)) in slices.into_iter().zip(data.items.iter_mut()).enumerate() { - let mut p = &mut mmsghdr.msg_hdr; - p.msg_iov = slice.as_ref().as_ptr() as *mut libc::iovec; - p.msg_iovlen = slice.as_ref().len() as _; - count = i + 1; - } - - let timeout_ptr = timeout - .as_mut() - .map_or_else(std::ptr::null_mut, |t| t as *mut _ as *mut libc::timespec); - - let received = Errno::result(unsafe { - libc::recvmmsg( - fd, - data.items.as_mut_ptr(), - count as _, - flags.bits() as _, - timeout_ptr, - ) - })? as usize; - - Ok(MultiResults { - rmm: data, - current_index: 0, - received, - }) -} - -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", -))] -#[derive(Debug)] -/// Iterator over results of [`recvmmsg`]/[`sendmmsg`] -/// -/// -pub struct MultiResults<'a, S> { - // preallocated structures - rmm: &'a MultiHeaders<S>, - current_index: usize, - received: usize, -} - -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", -))] -impl<'a, S> Iterator for MultiResults<'a, S> -where - S: Copy + SockaddrLike, -{ - type Item = RecvMsg<'a, 'a, S>; - - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - fn next(&mut self) -> Option<Self::Item> { - if self.current_index >= self.received { - return None; - } - let mmsghdr = self.rmm.items[self.current_index]; - - // as long as we are not reading past the index writen by recvmmsg - address - // will be initialized - let address = unsafe { self.rmm.addresses[self.current_index].assume_init() }; - - self.current_index += 1; - Some(unsafe { - read_mhdr( - mmsghdr.msg_hdr, - mmsghdr.msg_len as isize, - self.rmm.msg_controllen, - address, - ) - }) - } -} - -impl<'a, S> RecvMsg<'_, 'a, S> { - /// Iterate over the filled io slices pointed by this msghdr - pub fn iovs(&self) -> IoSliceIterator<'a> { - IoSliceIterator { - index: 0, - remaining: self.bytes, - slices: unsafe { - // safe for as long as mgdr is properly initialized and references are valid. - // for multi messages API we initialize it with an empty - // slice and replace with a concrete buffer - // for single message API we hold a lifetime reference to ioslices - std::slice::from_raw_parts(self.mhdr.msg_iov as *const _, self.mhdr.msg_iovlen as _) - }, - } - } -} - -#[derive(Debug)] -pub struct IoSliceIterator<'a> { - index: usize, - remaining: usize, - slices: &'a [IoSlice<'a>], -} - -impl<'a> Iterator for IoSliceIterator<'a> { - type Item = &'a [u8]; - - fn next(&mut self) -> Option<Self::Item> { - if self.index >= self.slices.len() { - return None; - } - let slice = &self.slices[self.index][..self.remaining.min(self.slices[self.index].len())]; - self.remaining -= slice.len(); - self.index += 1; - if slice.is_empty() { - return None; - } - - Some(slice) - } -} - -// test contains both recvmmsg and timestaping which is linux only -// there are existing tests for recvmmsg only in tests/ -#[cfg(target_os = "linux")] -#[cfg(test)] -mod test { - use crate::sys::socket::{AddressFamily, ControlMessageOwned}; - use crate::*; - use std::str::FromStr; - - #[cfg_attr(qemu, ignore)] - #[test] - fn test_recvmm2() -> crate::Result<()> { - use crate::sys::socket::{ - sendmsg, setsockopt, socket, sockopt::Timestamping, MsgFlags, SockFlag, SockType, - SockaddrIn, TimestampingFlag, - }; - use std::io::{IoSlice, IoSliceMut}; - - let sock_addr = SockaddrIn::from_str("127.0.0.1:6790").unwrap(); - - let ssock = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - )?; - - let rsock = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::SOCK_NONBLOCK, - None, - )?; - - crate::sys::socket::bind(rsock, &sock_addr)?; - - setsockopt(rsock, Timestamping, &TimestampingFlag::all())?; - - let sbuf = (0..400).map(|i| i as u8).collect::<Vec<_>>(); - - let mut recv_buf = vec![0; 1024]; - - let mut recv_iovs = Vec::new(); - let mut pkt_iovs = Vec::new(); - - for (ix, chunk) in recv_buf.chunks_mut(256).enumerate() { - pkt_iovs.push(IoSliceMut::new(chunk)); - if ix % 2 == 1 { - recv_iovs.push(pkt_iovs); - pkt_iovs = Vec::new(); - } - } - drop(pkt_iovs); - - let flags = MsgFlags::empty(); - let iov1 = [IoSlice::new(&sbuf)]; - - let cmsg = cmsg_space!(crate::sys::socket::Timestamps); - sendmsg(ssock, &iov1, &[], flags, Some(&sock_addr)).unwrap(); - - let mut data = super::MultiHeaders::<()>::preallocate(recv_iovs.len(), Some(cmsg)); - - let t = sys::time::TimeSpec::from_duration(std::time::Duration::from_secs(10)); - - let recv = super::recvmmsg(rsock, &mut data, recv_iovs.iter(), flags, Some(t))?; - - for rmsg in recv { - #[cfg(not(any(qemu, target_arch = "aarch64")))] - let mut saw_time = false; - let mut recvd = 0; - for cmsg in rmsg.cmsgs() { - if let ControlMessageOwned::ScmTimestampsns(timestamps) = cmsg { - let ts = timestamps.system; - - let sys_time = - crate::time::clock_gettime(crate::time::ClockId::CLOCK_REALTIME)?; - let diff = if ts > sys_time { - ts - sys_time - } else { - sys_time - ts - }; - assert!(std::time::Duration::from(diff).as_secs() < 60); - #[cfg(not(any(qemu, target_arch = "aarch64")))] - { - saw_time = true; - } - } - } - - #[cfg(not(any(qemu, target_arch = "aarch64")))] - assert!(saw_time); - - for iov in rmsg.iovs() { - recvd += iov.len(); - } - assert_eq!(recvd, 400); - } - - Ok(()) - } -} -unsafe fn read_mhdr<'a, 'i, S>( - mhdr: msghdr, - r: isize, - msg_controllen: usize, - address: S, -) -> RecvMsg<'a, 'i, S> - where S: SockaddrLike -{ - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - let cmsghdr = { - if mhdr.msg_controllen > 0 { - debug_assert!(!mhdr.msg_control.is_null()); - debug_assert!(msg_controllen >= mhdr.msg_controllen as usize); - CMSG_FIRSTHDR(&mhdr as *const msghdr) - } else { - ptr::null() - }.as_ref() - }; - - RecvMsg { - bytes: r as usize, - cmsghdr, - address: Some(address), - flags: MsgFlags::from_bits_truncate(mhdr.msg_flags), - mhdr, - iobufs: std::marker::PhantomData, - } -} - -/// Pack pointers to various structures into into msghdr -/// -/// # Safety -/// `iov_buffer` and `iov_buffer_len` must point to a slice -/// of `IoSliceMut` and number of available elements or be a null pointer and 0 -/// -/// `cmsg_buffer` and `cmsg_capacity` must point to a byte buffer used -/// to store control headers later or be a null pointer and 0 if control -/// headers are not used -/// -/// Buffers must remain valid for the whole lifetime of msghdr -unsafe fn pack_mhdr_to_receive<S>( - iov_buffer: *const IoSliceMut, - iov_buffer_len: usize, - cmsg_buffer: *const u8, - cmsg_capacity: usize, - address: *mut S, -) -> msghdr - where - S: SockaddrLike -{ - // Musl's msghdr has private fields, so this is the only way to - // initialize it. - let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed(); - let p = mhdr.as_mut_ptr(); - (*p).msg_name = (*address).as_mut_ptr() as *mut c_void; - (*p).msg_namelen = S::size(); - (*p).msg_iov = iov_buffer as *mut iovec; - (*p).msg_iovlen = iov_buffer_len as _; - (*p).msg_control = cmsg_buffer as *mut c_void; - (*p).msg_controllen = cmsg_capacity as _; - (*p).msg_flags = 0; - mhdr.assume_init() -} - -fn pack_mhdr_to_send<'a, I, C, S>( - cmsg_buffer: &mut [u8], - iov: I, - cmsgs: C, - addr: Option<&S> -) -> msghdr - where - I: AsRef<[IoSlice<'a>]>, - C: AsRef<[ControlMessage<'a>]>, - S: SockaddrLike + 'a -{ - let capacity = cmsg_buffer.len(); - - // The message header must be initialized before the individual cmsgs. - let cmsg_ptr = if capacity > 0 { - cmsg_buffer.as_ptr() as *mut c_void - } else { - ptr::null_mut() - }; - - let mhdr = unsafe { - // Musl's msghdr has private fields, so this is the only way to - // initialize it. - let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed(); - let p = mhdr.as_mut_ptr(); - (*p).msg_name = addr.map(S::as_ptr).unwrap_or(ptr::null()) as *mut _; - (*p).msg_namelen = addr.map(S::len).unwrap_or(0); - // transmute iov into a mutable pointer. sendmsg doesn't really mutate - // the buffer, but the standard says that it takes a mutable pointer - (*p).msg_iov = iov.as_ref().as_ptr() as *mut _; - (*p).msg_iovlen = iov.as_ref().len() as _; - (*p).msg_control = cmsg_ptr; - (*p).msg_controllen = capacity as _; - (*p).msg_flags = 0; - mhdr.assume_init() - }; - - // Encode each cmsg. This must happen after initializing the header because - // CMSG_NEXT_HDR and friends read the msg_control and msg_controllen fields. - // CMSG_FIRSTHDR is always safe - let mut pmhdr: *mut cmsghdr = unsafe { CMSG_FIRSTHDR(&mhdr as *const msghdr) }; - for cmsg in cmsgs.as_ref() { - assert_ne!(pmhdr, ptr::null_mut()); - // Safe because we know that pmhdr is valid, and we initialized it with - // sufficient space - unsafe { cmsg.encode_into(pmhdr) }; - // Safe because mhdr is valid - pmhdr = unsafe { CMSG_NXTHDR(&mhdr as *const msghdr, pmhdr) }; - } - - mhdr -} - -/// Receive message in scatter-gather vectors from a socket, and -/// optionally receive ancillary data into the provided buffer. -/// If no ancillary data is desired, use () as the type parameter. -/// -/// # Arguments -/// -/// * `fd`: Socket file descriptor -/// * `iov`: Scatter-gather list of buffers to receive the message -/// * `cmsg_buffer`: Space to receive ancillary data. Should be created by -/// [`cmsg_space!`](../../macro.cmsg_space.html) -/// * `flags`: Optional flags passed directly to the operating system. -/// -/// # References -/// [recvmsg(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html) -pub fn recvmsg<'a, 'outer, 'inner, S>(fd: RawFd, iov: &'outer mut [IoSliceMut<'inner>], - mut cmsg_buffer: Option<&'a mut Vec<u8>>, - flags: MsgFlags) -> Result<RecvMsg<'a, 'inner, S>> - where S: SockaddrLike + 'a, - 'inner: 'outer -{ - let mut address = mem::MaybeUninit::uninit(); - - let (msg_control, msg_controllen) = cmsg_buffer.as_mut() - .map(|v| (v.as_mut_ptr(), v.capacity())) - .unwrap_or((ptr::null_mut(), 0)); - let mut mhdr = unsafe { - pack_mhdr_to_receive(iov.as_ref().as_ptr(), iov.len(), msg_control, msg_controllen, address.as_mut_ptr()) - }; - - let ret = unsafe { libc::recvmsg(fd, &mut mhdr, flags.bits()) }; - - let r = Errno::result(ret)?; - - Ok(unsafe { read_mhdr(mhdr, r, msg_controllen, address.assume_init()) }) -} -} - -/// Create an endpoint for communication -/// -/// The `protocol` specifies a particular protocol to be used with the -/// socket. Normally only a single protocol exists to support a -/// particular socket type within a given protocol family, in which case -/// protocol can be specified as `None`. However, it is possible that many -/// protocols may exist, in which case a particular protocol must be -/// specified in this manner. -/// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html) -pub fn socket<T: Into<Option<SockProtocol>>>( - domain: AddressFamily, - ty: SockType, - flags: SockFlag, - protocol: T, -) -> Result<RawFd> { - let protocol = match protocol.into() { - None => 0, - Some(p) => p as c_int, - }; - - // SockFlags are usually embedded into `ty`, but we don't do that in `nix` because it's a - // little easier to understand by separating it out. So we have to merge these bitfields - // here. - let mut ty = ty as c_int; - ty |= flags.bits(); - - let res = unsafe { libc::socket(domain as c_int, ty, protocol) }; - - Errno::result(res) -} - -/// Create a pair of connected sockets -/// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/socketpair.html) -pub fn socketpair<T: Into<Option<SockProtocol>>>( - domain: AddressFamily, - ty: SockType, - protocol: T, - flags: SockFlag, -) -> Result<(RawFd, RawFd)> { - let protocol = match protocol.into() { - None => 0, - Some(p) => p as c_int, - }; - - // SockFlags are usually embedded into `ty`, but we don't do that in `nix` because it's a - // little easier to understand by separating it out. So we have to merge these bitfields - // here. - let mut ty = ty as c_int; - ty |= flags.bits(); - - let mut fds = [-1, -1]; - - let res = unsafe { - libc::socketpair(domain as c_int, ty, protocol, fds.as_mut_ptr()) - }; - Errno::result(res)?; - - Ok((fds[0], fds[1])) -} - -/// Listen for connections on a socket -/// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html) -pub fn listen(sockfd: RawFd, backlog: usize) -> Result<()> { - let res = unsafe { libc::listen(sockfd, backlog as c_int) }; - - Errno::result(res).map(drop) -} - -/// Bind a name to a socket -/// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html) -pub fn bind(fd: RawFd, addr: &dyn SockaddrLike) -> Result<()> { - let res = unsafe { libc::bind(fd, addr.as_ptr(), addr.len()) }; - - Errno::result(res).map(drop) -} - -/// Accept a connection on a socket -/// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html) -pub fn accept(sockfd: RawFd) -> Result<RawFd> { - let res = unsafe { libc::accept(sockfd, ptr::null_mut(), ptr::null_mut()) }; - - Errno::result(res) -} - -/// Accept a connection on a socket -/// -/// [Further reading](https://man7.org/linux/man-pages/man2/accept.2.html) -#[cfg(any( - all( - target_os = "android", - any( - target_arch = "aarch64", - target_arch = "x86", - target_arch = "x86_64" - ) - ), - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd" -))] -pub fn accept4(sockfd: RawFd, flags: SockFlag) -> Result<RawFd> { - let res = unsafe { - libc::accept4(sockfd, ptr::null_mut(), ptr::null_mut(), flags.bits()) - }; - - Errno::result(res) -} - -/// Initiate a connection on a socket -/// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html) -pub fn connect(fd: RawFd, addr: &dyn SockaddrLike) -> Result<()> { - let res = unsafe { libc::connect(fd, addr.as_ptr(), addr.len()) }; - - Errno::result(res).map(drop) -} - -/// Receive data from a connection-oriented socket. Returns the number of -/// bytes read -/// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recv.html) -pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result<usize> { - unsafe { - let ret = libc::recv( - sockfd, - buf.as_ptr() as *mut c_void, - buf.len() as size_t, - flags.bits(), - ); - - Errno::result(ret).map(|r| r as usize) - } -} - -/// Receive data from a connectionless or connection-oriented socket. Returns -/// the number of bytes read and, for connectionless sockets, the socket -/// address of the sender. -/// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html) -pub fn recvfrom<T: SockaddrLike>( - sockfd: RawFd, - buf: &mut [u8], -) -> Result<(usize, Option<T>)> { - unsafe { - let mut addr = mem::MaybeUninit::<T>::uninit(); - let mut len = mem::size_of_val(&addr) as socklen_t; - - let ret = Errno::result(libc::recvfrom( - sockfd, - buf.as_ptr() as *mut c_void, - buf.len() as size_t, - 0, - addr.as_mut_ptr() as *mut libc::sockaddr, - &mut len as *mut socklen_t, - ))? as usize; - - Ok(( - ret, - T::from_raw( - addr.assume_init().as_ptr() as *const libc::sockaddr, - Some(len), - ), - )) - } -} - -/// Send a message to a socket -/// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html) -pub fn sendto( - fd: RawFd, - buf: &[u8], - addr: &dyn SockaddrLike, - flags: MsgFlags, -) -> Result<usize> { - let ret = unsafe { - libc::sendto( - fd, - buf.as_ptr() as *const c_void, - buf.len() as size_t, - flags.bits(), - addr.as_ptr(), - addr.len(), - ) - }; - - Errno::result(ret).map(|r| r as usize) -} - -/// Send data to a connection-oriented socket. Returns the number of bytes read -/// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html) -pub fn send(fd: RawFd, buf: &[u8], flags: MsgFlags) -> Result<usize> { - let ret = unsafe { - libc::send( - fd, - buf.as_ptr() as *const c_void, - buf.len() as size_t, - flags.bits(), - ) - }; - - Errno::result(ret).map(|r| r as usize) -} - -/* - * - * ===== Socket Options ===== - * - */ - -/// Represents a socket option that can be retrieved. -pub trait GetSockOpt: Copy { - type Val; - - /// Look up the value of this socket option on the given socket. - fn get(&self, fd: RawFd) -> Result<Self::Val>; -} - -/// Represents a socket option that can be set. -pub trait SetSockOpt: Clone { - type Val; - - /// Set the value of this socket option on the given socket. - fn set(&self, fd: RawFd, val: &Self::Val) -> Result<()>; -} - -/// Get the current value for the requested socket option -/// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html) -pub fn getsockopt<O: GetSockOpt>(fd: RawFd, opt: O) -> Result<O::Val> { - opt.get(fd) -} - -/// Sets the value for the requested socket option -/// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html) -/// -/// # Examples -/// -/// ``` -/// use nix::sys::socket::setsockopt; -/// use nix::sys::socket::sockopt::KeepAlive; -/// use std::net::TcpListener; -/// use std::os::unix::io::AsRawFd; -/// -/// let listener = TcpListener::bind("0.0.0.0:0").unwrap(); -/// let fd = listener.as_raw_fd(); -/// let res = setsockopt(fd, KeepAlive, &true); -/// assert!(res.is_ok()); -/// ``` -pub fn setsockopt<O: SetSockOpt>( - fd: RawFd, - opt: O, - val: &O::Val, -) -> Result<()> { - opt.set(fd, val) -} - -/// Get the address of the peer connected to the socket `fd`. -/// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpeername.html) -pub fn getpeername<T: SockaddrLike>(fd: RawFd) -> Result<T> { - unsafe { - let mut addr = mem::MaybeUninit::<T>::uninit(); - let mut len = T::size(); - - let ret = libc::getpeername( - fd, - addr.as_mut_ptr() as *mut libc::sockaddr, - &mut len, - ); - - Errno::result(ret)?; - - T::from_raw(addr.assume_init().as_ptr(), Some(len)).ok_or(Errno::EINVAL) - } -} - -/// Get the current address to which the socket `fd` is bound. -/// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html) -pub fn getsockname<T: SockaddrLike>(fd: RawFd) -> Result<T> { - unsafe { - let mut addr = mem::MaybeUninit::<T>::uninit(); - let mut len = T::size(); - - let ret = libc::getsockname( - fd, - addr.as_mut_ptr() as *mut libc::sockaddr, - &mut len, - ); - - Errno::result(ret)?; - - T::from_raw(addr.assume_init().as_ptr(), Some(len)).ok_or(Errno::EINVAL) - } -} - -/// Return the appropriate `SockAddr` type from a `sockaddr_storage` of a -/// certain size. -/// -/// In C this would usually be done by casting. The `len` argument -/// should be the number of bytes in the `sockaddr_storage` that are actually -/// allocated and valid. It must be at least as large as all the useful parts -/// of the structure. Note that in the case of a `sockaddr_un`, `len` need not -/// include the terminating null. -#[deprecated( - since = "0.24.0", - note = "use SockaddrLike or SockaddrStorage instead" -)] -#[allow(deprecated)] -pub fn sockaddr_storage_to_addr( - addr: &sockaddr_storage, - len: usize, -) -> Result<SockAddr> { - assert!(len <= mem::size_of::<sockaddr_storage>()); - if len < mem::size_of_val(&addr.ss_family) { - return Err(Errno::ENOTCONN); - } - - match c_int::from(addr.ss_family) { - #[cfg(feature = "net")] - libc::AF_INET => { - assert!(len >= mem::size_of::<sockaddr_in>()); - let sin = unsafe { - *(addr as *const sockaddr_storage as *const sockaddr_in) - }; - Ok(SockAddr::Inet(InetAddr::V4(sin))) - } - #[cfg(feature = "net")] - libc::AF_INET6 => { - assert!(len >= mem::size_of::<sockaddr_in6>()); - let sin6 = unsafe { *(addr as *const _ as *const sockaddr_in6) }; - Ok(SockAddr::Inet(InetAddr::V6(sin6))) - } - libc::AF_UNIX => unsafe { - let sun = *(addr as *const _ as *const sockaddr_un); - let sun_len = len.try_into().unwrap(); - Ok(SockAddr::Unix(UnixAddr::from_raw_parts(sun, sun_len))) - }, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg(feature = "net")] - libc::AF_PACKET => { - use libc::sockaddr_ll; - // Don't assert anything about the size. - // Apparently the Linux kernel can return smaller sizes when - // the value in the last element of sockaddr_ll (`sll_addr`) is - // smaller than the declared size of that field - let sll = unsafe { *(addr as *const _ as *const sockaddr_ll) }; - Ok(SockAddr::Link(LinkAddr(sll))) - } - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_NETLINK => { - use libc::sockaddr_nl; - let snl = unsafe { *(addr as *const _ as *const sockaddr_nl) }; - Ok(SockAddr::Netlink(NetlinkAddr(snl))) - } - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_ALG => { - use libc::sockaddr_alg; - let salg = unsafe { *(addr as *const _ as *const sockaddr_alg) }; - Ok(SockAddr::Alg(AlgAddr(salg))) - } - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_VSOCK => { - use libc::sockaddr_vm; - let svm = unsafe { *(addr as *const _ as *const sockaddr_vm) }; - Ok(SockAddr::Vsock(VsockAddr(svm))) - } - af => panic!("unexpected address family {}", af), - } -} - -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum Shutdown { - /// Further receptions will be disallowed. - Read, - /// Further transmissions will be disallowed. - Write, - /// Further receptions and transmissions will be disallowed. - Both, -} - -/// Shut down part of a full-duplex connection. -/// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/shutdown.html) -pub fn shutdown(df: RawFd, how: Shutdown) -> Result<()> { - unsafe { - use libc::shutdown; - - let how = match how { - Shutdown::Read => libc::SHUT_RD, - Shutdown::Write => libc::SHUT_WR, - Shutdown::Both => libc::SHUT_RDWR, - }; - - Errno::result(shutdown(df, how)).map(drop) - } -} - -#[cfg(test)] -mod tests { - #[test] - fn can_use_cmsg_space() { - let _ = cmsg_space!(u8); - } -} diff --git a/vendor/nix/src/sys/socket/sockopt.rs b/vendor/nix/src/sys/socket/sockopt.rs deleted file mode 100644 index 06e9ee456..000000000 --- a/vendor/nix/src/sys/socket/sockopt.rs +++ /dev/null @@ -1,1422 +0,0 @@ -//! Socket options as used by `setsockopt` and `getsockopt`. -use super::{GetSockOpt, SetSockOpt}; -use crate::errno::Errno; -use crate::sys::time::TimeVal; -use crate::Result; -use cfg_if::cfg_if; -use libc::{self, c_int, c_void, socklen_t}; -use std::ffi::{OsStr, OsString}; -use std::{ - convert::TryFrom, - mem::{self, MaybeUninit} -}; -#[cfg(target_family = "unix")] -use std::os::unix::ffi::OsStrExt; -use std::os::unix::io::RawFd; - -// Constants -// TCP_CA_NAME_MAX isn't defined in user space include files -#[cfg(any(target_os = "freebsd", target_os = "linux"))] -#[cfg(feature = "net")] -const TCP_CA_NAME_MAX: usize = 16; - -/// Helper for implementing `SetSockOpt` for a given socket option. See -/// [`::sys::socket::SetSockOpt`](sys/socket/trait.SetSockOpt.html). -/// -/// This macro aims to help implementing `SetSockOpt` for different socket options that accept -/// different kinds of data to be used with `setsockopt`. -/// -/// Instead of using this macro directly consider using `sockopt_impl!`, especially if the option -/// you are implementing represents a simple type. -/// -/// # Arguments -/// -/// * `$name:ident`: name of the type you want to implement `SetSockOpt` for. -/// * `$level:expr` : socket layer, or a `protocol level`: could be *raw sockets* -/// (`libc::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`), -/// and more. Please refer to your system manual for more options. Will be passed as the second -/// argument (`level`) to the `setsockopt` call. -/// * `$flag:path`: a flag name to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`, -/// `libc::IP_ADD_MEMBERSHIP` and others. Will be passed as the third argument (`option_name`) -/// to the `setsockopt` call. -/// * Type of the value that you are going to set. -/// * Type that implements the `Set` trait for the type from the previous item (like `SetBool` for -/// `bool`, `SetUsize` for `usize`, etc.). -macro_rules! setsockopt_impl { - ($name:ident, $level:expr, $flag:path, $ty:ty, $setter:ty) => { - impl SetSockOpt for $name { - type Val = $ty; - - fn set(&self, fd: RawFd, val: &$ty) -> Result<()> { - unsafe { - let setter: $setter = Set::new(val); - - let res = libc::setsockopt( - fd, - $level, - $flag, - setter.ffi_ptr(), - setter.ffi_len(), - ); - Errno::result(res).map(drop) - } - } - } - }; -} - -/// Helper for implementing `GetSockOpt` for a given socket option. See -/// [`::sys::socket::GetSockOpt`](sys/socket/trait.GetSockOpt.html). -/// -/// This macro aims to help implementing `GetSockOpt` for different socket options that accept -/// different kinds of data to be use with `getsockopt`. -/// -/// Instead of using this macro directly consider using `sockopt_impl!`, especially if the option -/// you are implementing represents a simple type. -/// -/// # Arguments -/// -/// * Name of the type you want to implement `GetSockOpt` for. -/// * Socket layer, or a `protocol level`: could be *raw sockets* (`lic::SOL_SOCKET`), *ip -/// protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`), and more. Please refer -/// to your system manual for more options. Will be passed as the second argument (`level`) to -/// the `getsockopt` call. -/// * A flag to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`, -/// `libc::SO_ORIGINAL_DST` and others. Will be passed as the third argument (`option_name`) to -/// the `getsockopt` call. -/// * Type of the value that you are going to get. -/// * Type that implements the `Get` trait for the type from the previous item (`GetBool` for -/// `bool`, `GetUsize` for `usize`, etc.). -macro_rules! getsockopt_impl { - ($name:ident, $level:expr, $flag:path, $ty:ty, $getter:ty) => { - impl GetSockOpt for $name { - type Val = $ty; - - fn get(&self, fd: RawFd) -> Result<$ty> { - unsafe { - let mut getter: $getter = Get::uninit(); - - let res = libc::getsockopt( - fd, - $level, - $flag, - getter.ffi_ptr(), - getter.ffi_len(), - ); - Errno::result(res)?; - - match <$ty>::try_from(getter.assume_init()) { - Err(_) => Err(Errno::EINVAL), - Ok(r) => Ok(r) - } - } - } - } - }; -} - -/// Helper to generate the sockopt accessors. See -/// [`::sys::socket::GetSockOpt`](sys/socket/trait.GetSockOpt.html) and -/// [`::sys::socket::SetSockOpt`](sys/socket/trait.SetSockOpt.html). -/// -/// This macro aims to help implementing `GetSockOpt` and `SetSockOpt` for different socket options -/// that accept different kinds of data to be use with `getsockopt` and `setsockopt` respectively. -/// -/// Basically this macro wraps up the [`getsockopt_impl!`](macro.getsockopt_impl.html) and -/// [`setsockopt_impl!`](macro.setsockopt_impl.html) macros. -/// -/// # Arguments -/// -/// * `GetOnly`, `SetOnly` or `Both`: whether you want to implement only getter, only setter or -/// both of them. -/// * `$name:ident`: name of type `GetSockOpt`/`SetSockOpt` will be implemented for. -/// * `$level:expr` : socket layer, or a `protocol level`: could be *raw sockets* -/// (`lic::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`), -/// and more. Please refer to your system manual for more options. Will be passed as the second -/// argument (`level`) to the `getsockopt`/`setsockopt` call. -/// * `$flag:path`: a flag name to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`, -/// `libc::IP_ADD_MEMBERSHIP` and others. Will be passed as the third argument (`option_name`) -/// to the `setsockopt`/`getsockopt` call. -/// * `$ty:ty`: type of the value that will be get/set. -/// * `$getter:ty`: `Get` implementation; optional; only for `GetOnly` and `Both`. -/// * `$setter:ty`: `Set` implementation; optional; only for `SetOnly` and `Both`. -// Some targets don't use all rules. -#[allow(unknown_lints)] -#[allow(unused_macro_rules)] -macro_rules! sockopt_impl { - ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, bool) => { - sockopt_impl!($(#[$attr])* - $name, GetOnly, $level, $flag, bool, GetBool); - }; - - ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, u8) => { - sockopt_impl!($(#[$attr])* $name, GetOnly, $level, $flag, u8, GetU8); - }; - - ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, usize) => - { - sockopt_impl!($(#[$attr])* - $name, GetOnly, $level, $flag, usize, GetUsize); - }; - - ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, bool) => { - sockopt_impl!($(#[$attr])* - $name, SetOnly, $level, $flag, bool, SetBool); - }; - - ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, u8) => { - sockopt_impl!($(#[$attr])* $name, SetOnly, $level, $flag, u8, SetU8); - }; - - ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, usize) => - { - sockopt_impl!($(#[$attr])* - $name, SetOnly, $level, $flag, usize, SetUsize); - }; - - ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, bool) => { - sockopt_impl!($(#[$attr])* - $name, Both, $level, $flag, bool, GetBool, SetBool); - }; - - ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, u8) => { - sockopt_impl!($(#[$attr])* - $name, Both, $level, $flag, u8, GetU8, SetU8); - }; - - ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, usize) => { - sockopt_impl!($(#[$attr])* - $name, Both, $level, $flag, usize, GetUsize, SetUsize); - }; - - ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, - OsString<$array:ty>) => - { - sockopt_impl!($(#[$attr])* - $name, Both, $level, $flag, OsString, GetOsString<$array>, - SetOsString); - }; - - /* - * Matchers with generic getter types must be placed at the end, so - * they'll only match _after_ specialized matchers fail - */ - ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, $ty:ty) => - { - sockopt_impl!($(#[$attr])* - $name, GetOnly, $level, $flag, $ty, GetStruct<$ty>); - }; - - ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, $ty:ty, - $getter:ty) => - { - $(#[$attr])* - #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] - pub struct $name; - - getsockopt_impl!($name, $level, $flag, $ty, $getter); - }; - - ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, $ty:ty) => - { - sockopt_impl!($(#[$attr])* - $name, SetOnly, $level, $flag, $ty, SetStruct<$ty>); - }; - - ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, $ty:ty, - $setter:ty) => - { - $(#[$attr])* - #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] - pub struct $name; - - setsockopt_impl!($name, $level, $flag, $ty, $setter); - }; - - ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, $ty:ty, - $getter:ty, $setter:ty) => - { - $(#[$attr])* - #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] - pub struct $name; - - setsockopt_impl!($name, $level, $flag, $ty, $setter); - getsockopt_impl!($name, $level, $flag, $ty, $getter); - }; - - ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, $ty:ty) => { - sockopt_impl!($(#[$attr])* - $name, Both, $level, $flag, $ty, GetStruct<$ty>, - SetStruct<$ty>); - }; -} - -/* - * - * ===== Define sockopts ===== - * - */ - -sockopt_impl!( - /// Enables local address reuse - ReuseAddr, - Both, - libc::SOL_SOCKET, - libc::SO_REUSEADDR, - bool -); -#[cfg(not(any(target_os = "illumos", target_os = "solaris")))] -sockopt_impl!( - /// Permits multiple AF_INET or AF_INET6 sockets to be bound to an - /// identical socket address. - ReusePort, - Both, - libc::SOL_SOCKET, - libc::SO_REUSEPORT, - bool -); -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Under most circumstances, TCP sends data when it is presented; when - /// outstanding data has not yet been acknowledged, it gathers small amounts - /// of output to be sent in a single packet once an acknowledgement is - /// received. For a small number of clients, such as window systems that - /// send a stream of mouse events which receive no replies, this - /// packetization may cause significant delays. The boolean option - /// TCP_NODELAY defeats this algorithm. - TcpNoDelay, - Both, - libc::IPPROTO_TCP, - libc::TCP_NODELAY, - bool -); -sockopt_impl!( - /// When enabled, a close(2) or shutdown(2) will not return until all - /// queued messages for the socket have been successfully sent or the - /// linger timeout has been reached. - Linger, - Both, - libc::SOL_SOCKET, - libc::SO_LINGER, - libc::linger -); -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Join a multicast group - IpAddMembership, - SetOnly, - libc::IPPROTO_IP, - libc::IP_ADD_MEMBERSHIP, - super::IpMembershipRequest -); -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Leave a multicast group. - IpDropMembership, - SetOnly, - libc::IPPROTO_IP, - libc::IP_DROP_MEMBERSHIP, - super::IpMembershipRequest -); -cfg_if! { - if #[cfg(any(target_os = "android", target_os = "linux"))] { - #[cfg(feature = "net")] - sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Join an IPv6 multicast group. - Ipv6AddMembership, SetOnly, libc::IPPROTO_IPV6, libc::IPV6_ADD_MEMBERSHIP, super::Ipv6MembershipRequest); - #[cfg(feature = "net")] - sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Leave an IPv6 multicast group. - Ipv6DropMembership, SetOnly, libc::IPPROTO_IPV6, libc::IPV6_DROP_MEMBERSHIP, super::Ipv6MembershipRequest); - } else if #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris"))] { - #[cfg(feature = "net")] - sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Join an IPv6 multicast group. - Ipv6AddMembership, SetOnly, libc::IPPROTO_IPV6, - libc::IPV6_JOIN_GROUP, super::Ipv6MembershipRequest); - #[cfg(feature = "net")] - sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Leave an IPv6 multicast group. - Ipv6DropMembership, SetOnly, libc::IPPROTO_IPV6, - libc::IPV6_LEAVE_GROUP, super::Ipv6MembershipRequest); - } -} -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Set or read the time-to-live value of outgoing multicast packets for - /// this socket. - IpMulticastTtl, - Both, - libc::IPPROTO_IP, - libc::IP_MULTICAST_TTL, - u8 -); -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Set or read a boolean integer argument that determines whether sent - /// multicast packets should be looped back to the local sockets. - IpMulticastLoop, - Both, - libc::IPPROTO_IP, - libc::IP_MULTICAST_LOOP, - bool -); -#[cfg(target_os = "linux")] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Set the protocol-defined priority for all packets to be - /// sent on this socket - Priority, - Both, - libc::SOL_SOCKET, - libc::SO_PRIORITY, - libc::c_int -); -#[cfg(target_os = "linux")] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Set or receive the Type-Of-Service (TOS) field that is - /// sent with every IP packet originating from this socket - IpTos, - Both, - libc::IPPROTO_IP, - libc::IP_TOS, - libc::c_int -); -#[cfg(target_os = "linux")] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Traffic class associated with outgoing packets - Ipv6TClass, - Both, - libc::IPPROTO_IPV6, - libc::IPV6_TCLASS, - libc::c_int -); -#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// If enabled, this boolean option allows binding to an IP address that - /// is nonlocal or does not (yet) exist. - IpFreebind, - Both, - libc::IPPROTO_IP, - libc::IP_FREEBIND, - bool -); -sockopt_impl!( - /// Specify the receiving timeout until reporting an error. - ReceiveTimeout, - Both, - libc::SOL_SOCKET, - libc::SO_RCVTIMEO, - TimeVal -); -sockopt_impl!( - /// Specify the sending timeout until reporting an error. - SendTimeout, - Both, - libc::SOL_SOCKET, - libc::SO_SNDTIMEO, - TimeVal -); -sockopt_impl!( - /// Set or get the broadcast flag. - Broadcast, - Both, - libc::SOL_SOCKET, - libc::SO_BROADCAST, - bool -); -sockopt_impl!( - /// If this option is enabled, out-of-band data is directly placed into - /// the receive data stream. - OobInline, - Both, - libc::SOL_SOCKET, - libc::SO_OOBINLINE, - bool -); -sockopt_impl!( - /// Get and clear the pending socket error. - SocketError, - GetOnly, - libc::SOL_SOCKET, - libc::SO_ERROR, - i32 -); -sockopt_impl!( - /// Set or get the don't route flag. - DontRoute, - Both, - libc::SOL_SOCKET, - libc::SO_DONTROUTE, - bool -); -sockopt_impl!( - /// Enable sending of keep-alive messages on connection-oriented sockets. - KeepAlive, - Both, - libc::SOL_SOCKET, - libc::SO_KEEPALIVE, - bool -); -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "ios" -))] -sockopt_impl!( - /// Get the credentials of the peer process of a connected unix domain - /// socket. - LocalPeerCred, - GetOnly, - 0, - libc::LOCAL_PEERCRED, - super::XuCred -); -#[cfg(any(target_os = "android", target_os = "linux"))] -sockopt_impl!( - /// Return the credentials of the foreign process connected to this socket. - PeerCredentials, - GetOnly, - libc::SOL_SOCKET, - libc::SO_PEERCRED, - super::UnixCredentials -); -#[cfg(any(target_os = "ios", target_os = "macos"))] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Specify the amount of time, in seconds, that the connection must be idle - /// before keepalive probes (if enabled) are sent. - TcpKeepAlive, - Both, - libc::IPPROTO_TCP, - libc::TCP_KEEPALIVE, - u32 -); -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux" -))] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// The time (in seconds) the connection needs to remain idle before TCP - /// starts sending keepalive probes - TcpKeepIdle, - Both, - libc::IPPROTO_TCP, - libc::TCP_KEEPIDLE, - u32 -); -cfg_if! { - if #[cfg(any(target_os = "android", target_os = "linux"))] { - sockopt_impl!( - /// The maximum segment size for outgoing TCP packets. - TcpMaxSeg, Both, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32); - } else { - sockopt_impl!( - /// The maximum segment size for outgoing TCP packets. - TcpMaxSeg, GetOnly, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32); - } -} -#[cfg(not(any(target_os = "openbsd", target_os = "haiku")))] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// The maximum number of keepalive probes TCP should send before - /// dropping the connection. - TcpKeepCount, - Both, - libc::IPPROTO_TCP, - libc::TCP_KEEPCNT, - u32 -); -#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] -sockopt_impl!( - #[allow(missing_docs)] - // Not documented by Linux! - TcpRepair, - Both, - libc::IPPROTO_TCP, - libc::TCP_REPAIR, - u32 -); -#[cfg(not(any(target_os = "openbsd", target_os = "haiku")))] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// The time (in seconds) between individual keepalive probes. - TcpKeepInterval, - Both, - libc::IPPROTO_TCP, - libc::TCP_KEEPINTVL, - u32 -); -#[cfg(any(target_os = "fuchsia", target_os = "linux"))] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Specifies the maximum amount of time in milliseconds that transmitted - /// data may remain unacknowledged before TCP will forcibly close the - /// corresponding connection - TcpUserTimeout, - Both, - libc::IPPROTO_TCP, - libc::TCP_USER_TIMEOUT, - u32 -); -sockopt_impl!( - /// Sets or gets the maximum socket receive buffer in bytes. - RcvBuf, - Both, - libc::SOL_SOCKET, - libc::SO_RCVBUF, - usize -); -sockopt_impl!( - /// Sets or gets the maximum socket send buffer in bytes. - SndBuf, - Both, - libc::SOL_SOCKET, - libc::SO_SNDBUF, - usize -); -#[cfg(any(target_os = "android", target_os = "linux"))] -sockopt_impl!( - /// Using this socket option, a privileged (`CAP_NET_ADMIN`) process can - /// perform the same task as `SO_RCVBUF`, but the `rmem_max limit` can be - /// overridden. - RcvBufForce, - SetOnly, - libc::SOL_SOCKET, - libc::SO_RCVBUFFORCE, - usize -); -#[cfg(any(target_os = "android", target_os = "linux"))] -sockopt_impl!( - /// Using this socket option, a privileged (`CAP_NET_ADMIN`) process can - /// perform the same task as `SO_SNDBUF`, but the `wmem_max` limit can be - /// overridden. - SndBufForce, - SetOnly, - libc::SOL_SOCKET, - libc::SO_SNDBUFFORCE, - usize -); -sockopt_impl!( - /// Gets the socket type as an integer. - SockType, - GetOnly, - libc::SOL_SOCKET, - libc::SO_TYPE, - super::SockType, - GetStruct<i32> -); -sockopt_impl!( - /// Returns a value indicating whether or not this socket has been marked to - /// accept connections with `listen(2)`. - AcceptConn, - GetOnly, - libc::SOL_SOCKET, - libc::SO_ACCEPTCONN, - bool -); -#[cfg(any(target_os = "android", target_os = "linux"))] -sockopt_impl!( - /// Bind this socket to a particular device like “eth0”. - BindToDevice, - Both, - libc::SOL_SOCKET, - libc::SO_BINDTODEVICE, - OsString<[u8; libc::IFNAMSIZ]> -); -#[cfg(any(target_os = "android", target_os = "linux"))] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - #[allow(missing_docs)] - // Not documented by Linux! - OriginalDst, - GetOnly, - libc::SOL_IP, - libc::SO_ORIGINAL_DST, - libc::sockaddr_in -); -#[cfg(any(target_os = "android", target_os = "linux"))] -sockopt_impl!( - #[allow(missing_docs)] - // Not documented by Linux! - Ip6tOriginalDst, - GetOnly, - libc::SOL_IPV6, - libc::IP6T_SO_ORIGINAL_DST, - libc::sockaddr_in6 -); -#[cfg(any(target_os = "linux"))] -sockopt_impl!( - /// Specifies exact type of timestamping information collected by the kernel - /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) - Timestamping, - Both, - libc::SOL_SOCKET, - libc::SO_TIMESTAMPING, - super::TimestampingFlag -); -#[cfg(not(target_os = "haiku"))] -sockopt_impl!( - /// Enable or disable the receiving of the `SO_TIMESTAMP` control message. - ReceiveTimestamp, - Both, - libc::SOL_SOCKET, - libc::SO_TIMESTAMP, - bool -); -#[cfg(all(target_os = "linux"))] -sockopt_impl!( - /// Enable or disable the receiving of the `SO_TIMESTAMPNS` control message. - ReceiveTimestampns, - Both, - libc::SOL_SOCKET, - libc::SO_TIMESTAMPNS, - bool -); -#[cfg(any(target_os = "android", target_os = "linux"))] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Setting this boolean option enables transparent proxying on this socket. - IpTransparent, - Both, - libc::SOL_IP, - libc::IP_TRANSPARENT, - bool -); -#[cfg(target_os = "openbsd")] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Allows the socket to be bound to addresses which are not local to the - /// machine, so it can be used to make a transparent proxy. - BindAny, - Both, - libc::SOL_SOCKET, - libc::SO_BINDANY, - bool -); -#[cfg(target_os = "freebsd")] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Can `bind(2)` to any address, even one not bound to any available - /// network interface in the system. - BindAny, - Both, - libc::IPPROTO_IP, - libc::IP_BINDANY, - bool -); -#[cfg(target_os = "linux")] -sockopt_impl!( - /// Set the mark for each packet sent through this socket (similar to the - /// netfilter MARK target but socket-based). - Mark, - Both, - libc::SOL_SOCKET, - libc::SO_MARK, - u32 -); -#[cfg(any(target_os = "android", target_os = "linux"))] -sockopt_impl!( - /// Enable or disable the receiving of the `SCM_CREDENTIALS` control - /// message. - PassCred, - Both, - libc::SOL_SOCKET, - libc::SO_PASSCRED, - bool -); -#[cfg(any(target_os = "freebsd", target_os = "linux"))] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// This option allows the caller to set the TCP congestion control - /// algorithm to be used, on a per-socket basis. - TcpCongestion, - Both, - libc::IPPROTO_TCP, - libc::TCP_CONGESTION, - OsString<[u8; TCP_CA_NAME_MAX]> -); -#[cfg(any( - target_os = "android", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", -))] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Pass an `IP_PKTINFO` ancillary message that contains a pktinfo - /// structure that supplies some information about the incoming packet. - Ipv4PacketInfo, - Both, - libc::IPPROTO_IP, - libc::IP_PKTINFO, - bool -); -#[cfg(any( - target_os = "android", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", -))] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// Set delivery of the `IPV6_PKTINFO` control message on incoming - /// datagrams. - Ipv6RecvPacketInfo, - Both, - libc::IPPROTO_IPV6, - libc::IPV6_RECVPKTINFO, - bool -); -#[cfg(any( - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", -))] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// The `recvmsg(2)` call returns a `struct sockaddr_dl` corresponding to - /// the interface on which the packet was received. - Ipv4RecvIf, - Both, - libc::IPPROTO_IP, - libc::IP_RECVIF, - bool -); -#[cfg(any( - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", -))] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// The `recvmsg(2)` call will return the destination IP address for a UDP - /// datagram. - Ipv4RecvDstAddr, - Both, - libc::IPPROTO_IP, - libc::IP_RECVDSTADDR, - bool -); -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// The `recvmsg(2)` call will return the destination IP address for a UDP - /// datagram. - Ipv4OrigDstAddr, - Both, - libc::IPPROTO_IP, - libc::IP_ORIGDSTADDR, - bool -); -#[cfg(target_os = "linux")] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - #[allow(missing_docs)] - // Not documented by Linux! - UdpGsoSegment, - Both, - libc::SOL_UDP, - libc::UDP_SEGMENT, - libc::c_int -); -#[cfg(target_os = "linux")] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - #[allow(missing_docs)] - // Not documented by Linux! - UdpGroSegment, - Both, - libc::IPPROTO_UDP, - libc::UDP_GRO, - bool -); -#[cfg(target_os = "linux")] -sockopt_impl!( - /// Configures the behavior of time-based transmission of packets, for use - /// with the `TxTime` control message. - TxTime, - Both, - libc::SOL_SOCKET, - libc::SO_TXTIME, - libc::sock_txtime -); -#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] -sockopt_impl!( - /// Indicates that an unsigned 32-bit value ancillary message (cmsg) should - /// be attached to received skbs indicating the number of packets dropped by - /// the socket since its creation. - RxqOvfl, - Both, - libc::SOL_SOCKET, - libc::SO_RXQ_OVFL, - libc::c_int -); -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// The socket is restricted to sending and receiving IPv6 packets only. - Ipv6V6Only, - Both, - libc::IPPROTO_IPV6, - libc::IPV6_V6ONLY, - bool -); -#[cfg(any(target_os = "android", target_os = "linux"))] -sockopt_impl!( - /// Enable extended reliable error message passing. - Ipv4RecvErr, - Both, - libc::IPPROTO_IP, - libc::IP_RECVERR, - bool -); -#[cfg(any(target_os = "android", target_os = "linux"))] -sockopt_impl!( - /// Control receiving of asynchronous error options. - Ipv6RecvErr, - Both, - libc::IPPROTO_IPV6, - libc::IPV6_RECVERR, - bool -); -#[cfg(any(target_os = "android", target_os = "linux"))] -sockopt_impl!( - /// Fetch the current system-estimated Path MTU. - IpMtu, - GetOnly, - libc::IPPROTO_IP, - libc::IP_MTU, - libc::c_int -); -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] -sockopt_impl!( - /// Set or retrieve the current time-to-live field that is used in every - /// packet sent from this socket. - Ipv4Ttl, - Both, - libc::IPPROTO_IP, - libc::IP_TTL, - libc::c_int -); -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] -sockopt_impl!( - /// Set the unicast hop limit for the socket. - Ipv6Ttl, - Both, - libc::IPPROTO_IPV6, - libc::IPV6_UNICAST_HOPS, - libc::c_int -); -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] -#[cfg(feature = "net")] -sockopt_impl!( - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - /// The `recvmsg(2)` call will return the destination IP address for a UDP - /// datagram. - Ipv6OrigDstAddr, - Both, - libc::IPPROTO_IPV6, - libc::IPV6_ORIGDSTADDR, - bool -); -#[cfg(any(target_os = "ios", target_os = "macos"))] -sockopt_impl!( - /// Set "don't fragment packet" flag on the IP packet. - IpDontFrag, - Both, - libc::IPPROTO_IP, - libc::IP_DONTFRAG, - bool -); -#[cfg(any( - target_os = "android", - target_os = "ios", - target_os = "linux", - target_os = "macos", -))] -sockopt_impl!( - /// Set "don't fragment packet" flag on the IPv6 packet. - Ipv6DontFrag, - Both, - libc::IPPROTO_IPV6, - libc::IPV6_DONTFRAG, - bool -); - -#[allow(missing_docs)] -// Not documented by Linux! -#[cfg(any(target_os = "android", target_os = "linux"))] -#[derive(Copy, Clone, Debug)] -pub struct AlgSetAeadAuthSize; - -// ALG_SET_AEAD_AUTH_SIZE read the length from passed `option_len` -// See https://elixir.bootlin.com/linux/v4.4/source/crypto/af_alg.c#L222 -#[cfg(any(target_os = "android", target_os = "linux"))] -impl SetSockOpt for AlgSetAeadAuthSize { - type Val = usize; - - fn set(&self, fd: RawFd, val: &usize) -> Result<()> { - unsafe { - let res = libc::setsockopt( - fd, - libc::SOL_ALG, - libc::ALG_SET_AEAD_AUTHSIZE, - ::std::ptr::null(), - *val as libc::socklen_t, - ); - Errno::result(res).map(drop) - } - } -} - -#[allow(missing_docs)] -// Not documented by Linux! -#[cfg(any(target_os = "android", target_os = "linux"))] -#[derive(Clone, Debug)] -pub struct AlgSetKey<T>(::std::marker::PhantomData<T>); - -#[cfg(any(target_os = "android", target_os = "linux"))] -impl<T> Default for AlgSetKey<T> { - fn default() -> Self { - AlgSetKey(Default::default()) - } -} - -#[cfg(any(target_os = "android", target_os = "linux"))] -impl<T> SetSockOpt for AlgSetKey<T> -where - T: AsRef<[u8]> + Clone, -{ - type Val = T; - - fn set(&self, fd: RawFd, val: &T) -> Result<()> { - unsafe { - let res = libc::setsockopt( - fd, - libc::SOL_ALG, - libc::ALG_SET_KEY, - val.as_ref().as_ptr() as *const _, - val.as_ref().len() as libc::socklen_t, - ); - Errno::result(res).map(drop) - } - } -} - -/* - * - * ===== Accessor helpers ===== - * - */ - -/// Helper trait that describes what is expected from a `GetSockOpt` getter. -trait Get<T> { - /// Returns an uninitialized value. - fn uninit() -> Self; - /// Returns a pointer to the stored value. This pointer will be passed to the system's - /// `getsockopt` call (`man 3p getsockopt`, argument `option_value`). - fn ffi_ptr(&mut self) -> *mut c_void; - /// Returns length of the stored value. This pointer will be passed to the system's - /// `getsockopt` call (`man 3p getsockopt`, argument `option_len`). - fn ffi_len(&mut self) -> *mut socklen_t; - /// Returns the hopefully initialized inner value. - unsafe fn assume_init(self) -> T; -} - -/// Helper trait that describes what is expected from a `SetSockOpt` setter. -trait Set<'a, T> { - /// Initialize the setter with a given value. - fn new(val: &'a T) -> Self; - /// Returns a pointer to the stored value. This pointer will be passed to the system's - /// `setsockopt` call (`man 3p setsockopt`, argument `option_value`). - fn ffi_ptr(&self) -> *const c_void; - /// Returns length of the stored value. This pointer will be passed to the system's - /// `setsockopt` call (`man 3p setsockopt`, argument `option_len`). - fn ffi_len(&self) -> socklen_t; -} - -/// Getter for an arbitrary `struct`. -struct GetStruct<T> { - len: socklen_t, - val: MaybeUninit<T>, -} - -impl<T> Get<T> for GetStruct<T> { - fn uninit() -> Self { - GetStruct { - len: mem::size_of::<T>() as socklen_t, - val: MaybeUninit::uninit(), - } - } - - fn ffi_ptr(&mut self) -> *mut c_void { - self.val.as_mut_ptr() as *mut c_void - } - - fn ffi_len(&mut self) -> *mut socklen_t { - &mut self.len - } - - unsafe fn assume_init(self) -> T { - assert_eq!( - self.len as usize, - mem::size_of::<T>(), - "invalid getsockopt implementation" - ); - self.val.assume_init() - } -} - -/// Setter for an arbitrary `struct`. -struct SetStruct<'a, T: 'static> { - ptr: &'a T, -} - -impl<'a, T> Set<'a, T> for SetStruct<'a, T> { - fn new(ptr: &'a T) -> SetStruct<'a, T> { - SetStruct { ptr } - } - - fn ffi_ptr(&self) -> *const c_void { - self.ptr as *const T as *const c_void - } - - fn ffi_len(&self) -> socklen_t { - mem::size_of::<T>() as socklen_t - } -} - -/// Getter for a boolean value. -struct GetBool { - len: socklen_t, - val: MaybeUninit<c_int>, -} - -impl Get<bool> for GetBool { - fn uninit() -> Self { - GetBool { - len: mem::size_of::<c_int>() as socklen_t, - val: MaybeUninit::uninit(), - } - } - - fn ffi_ptr(&mut self) -> *mut c_void { - self.val.as_mut_ptr() as *mut c_void - } - - fn ffi_len(&mut self) -> *mut socklen_t { - &mut self.len - } - - unsafe fn assume_init(self) -> bool { - assert_eq!( - self.len as usize, - mem::size_of::<c_int>(), - "invalid getsockopt implementation" - ); - self.val.assume_init() != 0 - } -} - -/// Setter for a boolean value. -struct SetBool { - val: c_int, -} - -impl<'a> Set<'a, bool> for SetBool { - fn new(val: &'a bool) -> SetBool { - SetBool { - val: i32::from(*val), - } - } - - fn ffi_ptr(&self) -> *const c_void { - &self.val as *const c_int as *const c_void - } - - fn ffi_len(&self) -> socklen_t { - mem::size_of::<c_int>() as socklen_t - } -} - -/// Getter for an `u8` value. -struct GetU8 { - len: socklen_t, - val: MaybeUninit<u8>, -} - -impl Get<u8> for GetU8 { - fn uninit() -> Self { - GetU8 { - len: mem::size_of::<u8>() as socklen_t, - val: MaybeUninit::uninit(), - } - } - - fn ffi_ptr(&mut self) -> *mut c_void { - self.val.as_mut_ptr() as *mut c_void - } - - fn ffi_len(&mut self) -> *mut socklen_t { - &mut self.len - } - - unsafe fn assume_init(self) -> u8 { - assert_eq!( - self.len as usize, - mem::size_of::<u8>(), - "invalid getsockopt implementation" - ); - self.val.assume_init() - } -} - -/// Setter for an `u8` value. -struct SetU8 { - val: u8, -} - -impl<'a> Set<'a, u8> for SetU8 { - fn new(val: &'a u8) -> SetU8 { - SetU8 { val: *val } - } - - fn ffi_ptr(&self) -> *const c_void { - &self.val as *const u8 as *const c_void - } - - fn ffi_len(&self) -> socklen_t { - mem::size_of::<c_int>() as socklen_t - } -} - -/// Getter for an `usize` value. -struct GetUsize { - len: socklen_t, - val: MaybeUninit<c_int>, -} - -impl Get<usize> for GetUsize { - fn uninit() -> Self { - GetUsize { - len: mem::size_of::<c_int>() as socklen_t, - val: MaybeUninit::uninit(), - } - } - - fn ffi_ptr(&mut self) -> *mut c_void { - self.val.as_mut_ptr() as *mut c_void - } - - fn ffi_len(&mut self) -> *mut socklen_t { - &mut self.len - } - - unsafe fn assume_init(self) -> usize { - assert_eq!( - self.len as usize, - mem::size_of::<c_int>(), - "invalid getsockopt implementation" - ); - self.val.assume_init() as usize - } -} - -/// Setter for an `usize` value. -struct SetUsize { - val: c_int, -} - -impl<'a> Set<'a, usize> for SetUsize { - fn new(val: &'a usize) -> SetUsize { - SetUsize { val: *val as c_int } - } - - fn ffi_ptr(&self) -> *const c_void { - &self.val as *const c_int as *const c_void - } - - fn ffi_len(&self) -> socklen_t { - mem::size_of::<c_int>() as socklen_t - } -} - -/// Getter for a `OsString` value. -struct GetOsString<T: AsMut<[u8]>> { - len: socklen_t, - val: MaybeUninit<T>, -} - -impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> { - fn uninit() -> Self { - GetOsString { - len: mem::size_of::<T>() as socklen_t, - val: MaybeUninit::uninit(), - } - } - - fn ffi_ptr(&mut self) -> *mut c_void { - self.val.as_mut_ptr() as *mut c_void - } - - fn ffi_len(&mut self) -> *mut socklen_t { - &mut self.len - } - - unsafe fn assume_init(self) -> OsString { - let len = self.len as usize; - let mut v = self.val.assume_init(); - OsStr::from_bytes(&v.as_mut()[0..len]).to_owned() - } -} - -/// Setter for a `OsString` value. -struct SetOsString<'a> { - val: &'a OsStr, -} - -impl<'a> Set<'a, OsString> for SetOsString<'a> { - fn new(val: &'a OsString) -> SetOsString { - SetOsString { - val: val.as_os_str(), - } - } - - fn ffi_ptr(&self) -> *const c_void { - self.val.as_bytes().as_ptr() as *const c_void - } - - fn ffi_len(&self) -> socklen_t { - self.val.len() as socklen_t - } -} - -#[cfg(test)] -mod test { - #[cfg(any(target_os = "android", target_os = "linux"))] - #[test] - fn can_get_peercred_on_unix_socket() { - use super::super::*; - - let (a, b) = socketpair( - AddressFamily::Unix, - SockType::Stream, - None, - SockFlag::empty(), - ) - .unwrap(); - let a_cred = getsockopt(a, super::PeerCredentials).unwrap(); - let b_cred = getsockopt(b, super::PeerCredentials).unwrap(); - assert_eq!(a_cred, b_cred); - assert_ne!(a_cred.pid(), 0); - } - - #[test] - fn is_socket_type_unix() { - use super::super::*; - use crate::unistd::close; - - let (a, b) = socketpair( - AddressFamily::Unix, - SockType::Stream, - None, - SockFlag::empty(), - ) - .unwrap(); - let a_type = getsockopt(a, super::SockType).unwrap(); - assert_eq!(a_type, SockType::Stream); - close(a).unwrap(); - close(b).unwrap(); - } - - #[test] - fn is_socket_type_dgram() { - use super::super::*; - use crate::unistd::close; - - let s = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .unwrap(); - let s_type = getsockopt(s, super::SockType).unwrap(); - assert_eq!(s_type, SockType::Datagram); - close(s).unwrap(); - } - - #[cfg(any(target_os = "freebsd", target_os = "linux"))] - #[test] - fn can_get_listen_on_tcp_socket() { - use super::super::*; - use crate::unistd::close; - - let s = socket( - AddressFamily::Inet, - SockType::Stream, - SockFlag::empty(), - None, - ) - .unwrap(); - let s_listening = getsockopt(s, super::AcceptConn).unwrap(); - assert!(!s_listening); - listen(s, 10).unwrap(); - let s_listening2 = getsockopt(s, super::AcceptConn).unwrap(); - assert!(s_listening2); - close(s).unwrap(); - } -} diff --git a/vendor/nix/src/sys/stat.rs b/vendor/nix/src/sys/stat.rs deleted file mode 100644 index 78203bfbe..000000000 --- a/vendor/nix/src/sys/stat.rs +++ /dev/null @@ -1,480 +0,0 @@ -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "openbsd"))] -pub use libc::c_uint; -#[cfg(any( - target_os = "netbsd", - target_os = "freebsd", - target_os = "dragonfly" -))] -pub use libc::c_ulong; -pub use libc::stat as FileStat; -pub use libc::{dev_t, mode_t}; - -#[cfg(not(target_os = "redox"))] -use crate::fcntl::{at_rawfd, AtFlags}; -use crate::sys::time::{TimeSpec, TimeVal}; -use crate::{errno::Errno, NixPath, Result}; -use std::mem; -use std::os::unix::io::RawFd; - -libc_bitflags!( - /// "File type" flags for `mknod` and related functions. - pub struct SFlag: mode_t { - S_IFIFO; - S_IFCHR; - S_IFDIR; - S_IFBLK; - S_IFREG; - S_IFLNK; - S_IFSOCK; - S_IFMT; - } -); - -libc_bitflags! { - /// "File mode / permissions" flags. - pub struct Mode: mode_t { - /// Read, write and execute for owner. - S_IRWXU; - /// Read for owner. - S_IRUSR; - /// Write for owner. - S_IWUSR; - /// Execute for owner. - S_IXUSR; - /// Read write and execute for group. - S_IRWXG; - /// Read fr group. - S_IRGRP; - /// Write for group. - S_IWGRP; - /// Execute for group. - S_IXGRP; - /// Read, write and execute for other. - S_IRWXO; - /// Read for other. - S_IROTH; - /// Write for other. - S_IWOTH; - /// Execute for other. - S_IXOTH; - /// Set user id on execution. - S_ISUID as mode_t; - /// Set group id on execution. - S_ISGID as mode_t; - S_ISVTX as mode_t; - } -} - -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "openbsd"))] -pub type type_of_file_flag = c_uint; -#[cfg(any( - target_os = "netbsd", - target_os = "freebsd", - target_os = "dragonfly" -))] -pub type type_of_file_flag = c_ulong; - -#[cfg(any( - target_os = "openbsd", - target_os = "netbsd", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "macos", - target_os = "ios" -))] -libc_bitflags! { - /// File flags. - #[cfg_attr(docsrs, doc(cfg(all())))] - pub struct FileFlag: type_of_file_flag { - /// The file may only be appended to. - SF_APPEND; - /// The file has been archived. - SF_ARCHIVED; - #[cfg(any(target_os = "dragonfly"))] - SF_CACHE; - /// The file may not be changed. - SF_IMMUTABLE; - /// Indicates a WAPBL journal file. - #[cfg(any(target_os = "netbsd"))] - SF_LOG; - /// Do not retain history for file - #[cfg(any(target_os = "dragonfly"))] - SF_NOHISTORY; - /// The file may not be renamed or deleted. - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - SF_NOUNLINK; - /// Mask of superuser changeable flags - SF_SETTABLE; - /// Snapshot is invalid. - #[cfg(any(target_os = "netbsd"))] - SF_SNAPINVAL; - /// The file is a snapshot file. - #[cfg(any(target_os = "netbsd", target_os = "freebsd"))] - SF_SNAPSHOT; - #[cfg(any(target_os = "dragonfly"))] - SF_XLINK; - /// The file may only be appended to. - UF_APPEND; - /// The file needs to be archived. - #[cfg(any(target_os = "freebsd"))] - UF_ARCHIVE; - #[cfg(any(target_os = "dragonfly"))] - UF_CACHE; - /// File is compressed at the file system level. - #[cfg(any(target_os = "macos", target_os = "ios"))] - UF_COMPRESSED; - /// The file may be hidden from directory listings at the application's - /// discretion. - #[cfg(any( - target_os = "freebsd", - target_os = "macos", - target_os = "ios", - ))] - UF_HIDDEN; - /// The file may not be changed. - UF_IMMUTABLE; - /// Do not dump the file. - UF_NODUMP; - #[cfg(any(target_os = "dragonfly"))] - UF_NOHISTORY; - /// The file may not be renamed or deleted. - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - UF_NOUNLINK; - /// The file is offline, or has the Windows and CIFS - /// `FILE_ATTRIBUTE_OFFLINE` attribute. - #[cfg(any(target_os = "freebsd"))] - UF_OFFLINE; - /// The directory is opaque when viewed through a union stack. - UF_OPAQUE; - /// The file is read only, and may not be written or appended. - #[cfg(any(target_os = "freebsd"))] - UF_READONLY; - /// The file contains a Windows reparse point. - #[cfg(any(target_os = "freebsd"))] - UF_REPARSE; - /// Mask of owner changeable flags. - UF_SETTABLE; - /// The file has the Windows `FILE_ATTRIBUTE_SPARSE_FILE` attribute. - #[cfg(any(target_os = "freebsd"))] - UF_SPARSE; - /// The file has the DOS, Windows and CIFS `FILE_ATTRIBUTE_SYSTEM` - /// attribute. - #[cfg(any(target_os = "freebsd"))] - UF_SYSTEM; - /// File renames and deletes are tracked. - #[cfg(any(target_os = "macos", target_os = "ios"))] - UF_TRACKED; - #[cfg(any(target_os = "dragonfly"))] - UF_XLINK; - } -} - -/// Create a special or ordinary file, by pathname. -pub fn mknod<P: ?Sized + NixPath>( - path: &P, - kind: SFlag, - perm: Mode, - dev: dev_t, -) -> Result<()> { - let res = path.with_nix_path(|cstr| unsafe { - libc::mknod(cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev) - })?; - - Errno::result(res).map(drop) -} - -/// Create a special or ordinary file, relative to a given directory. -#[cfg(not(any( - target_os = "ios", - target_os = "macos", - target_os = "redox", - target_os = "haiku" -)))] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub fn mknodat<P: ?Sized + NixPath>( - dirfd: RawFd, - path: &P, - kind: SFlag, - perm: Mode, - dev: dev_t, -) -> Result<()> { - let res = path.with_nix_path(|cstr| unsafe { - libc::mknodat( - dirfd, - cstr.as_ptr(), - kind.bits | perm.bits() as mode_t, - dev, - ) - })?; - - Errno::result(res).map(drop) -} - -#[cfg(target_os = "linux")] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub const fn major(dev: dev_t) -> u64 { - ((dev >> 32) & 0xffff_f000) | ((dev >> 8) & 0x0000_0fff) -} - -#[cfg(target_os = "linux")] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub const fn minor(dev: dev_t) -> u64 { - ((dev >> 12) & 0xffff_ff00) | ((dev) & 0x0000_00ff) -} - -#[cfg(target_os = "linux")] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub const fn makedev(major: u64, minor: u64) -> dev_t { - ((major & 0xffff_f000) << 32) - | ((major & 0x0000_0fff) << 8) - | ((minor & 0xffff_ff00) << 12) - | (minor & 0x0000_00ff) -} - -pub fn umask(mode: Mode) -> Mode { - let prev = unsafe { libc::umask(mode.bits() as mode_t) }; - Mode::from_bits(prev).expect("[BUG] umask returned invalid Mode") -} - -pub fn stat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> { - let mut dst = mem::MaybeUninit::uninit(); - let res = path.with_nix_path(|cstr| unsafe { - libc::stat(cstr.as_ptr(), dst.as_mut_ptr()) - })?; - - Errno::result(res)?; - - Ok(unsafe { dst.assume_init() }) -} - -pub fn lstat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> { - let mut dst = mem::MaybeUninit::uninit(); - let res = path.with_nix_path(|cstr| unsafe { - libc::lstat(cstr.as_ptr(), dst.as_mut_ptr()) - })?; - - Errno::result(res)?; - - Ok(unsafe { dst.assume_init() }) -} - -pub fn fstat(fd: RawFd) -> Result<FileStat> { - let mut dst = mem::MaybeUninit::uninit(); - let res = unsafe { libc::fstat(fd, dst.as_mut_ptr()) }; - - Errno::result(res)?; - - Ok(unsafe { dst.assume_init() }) -} - -#[cfg(not(target_os = "redox"))] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub fn fstatat<P: ?Sized + NixPath>( - dirfd: RawFd, - pathname: &P, - f: AtFlags, -) -> Result<FileStat> { - let mut dst = mem::MaybeUninit::uninit(); - let res = pathname.with_nix_path(|cstr| unsafe { - libc::fstatat( - dirfd, - cstr.as_ptr(), - dst.as_mut_ptr(), - f.bits() as libc::c_int, - ) - })?; - - Errno::result(res)?; - - Ok(unsafe { dst.assume_init() }) -} - -/// Change the file permission bits of the file specified by a file descriptor. -/// -/// # References -/// -/// [fchmod(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmod.html). -pub fn fchmod(fd: RawFd, mode: Mode) -> Result<()> { - let res = unsafe { libc::fchmod(fd, mode.bits() as mode_t) }; - - Errno::result(res).map(drop) -} - -/// Flags for `fchmodat` function. -#[derive(Clone, Copy, Debug)] -pub enum FchmodatFlags { - FollowSymlink, - NoFollowSymlink, -} - -/// Change the file permission bits. -/// -/// The file to be changed is determined relative to the directory associated -/// with the file descriptor `dirfd` or the current working directory -/// if `dirfd` is `None`. -/// -/// If `flag` is `FchmodatFlags::NoFollowSymlink` and `path` names a symbolic link, -/// then the mode of the symbolic link is changed. -/// -/// `fchmodat(None, path, mode, FchmodatFlags::FollowSymlink)` is identical to -/// a call `libc::chmod(path, mode)`. That's why `chmod` is unimplemented -/// in the `nix` crate. -/// -/// # References -/// -/// [fchmodat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmodat.html). -#[cfg(not(target_os = "redox"))] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub fn fchmodat<P: ?Sized + NixPath>( - dirfd: Option<RawFd>, - path: &P, - mode: Mode, - flag: FchmodatFlags, -) -> Result<()> { - let atflag = match flag { - FchmodatFlags::FollowSymlink => AtFlags::empty(), - FchmodatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW, - }; - let res = path.with_nix_path(|cstr| unsafe { - libc::fchmodat( - at_rawfd(dirfd), - cstr.as_ptr(), - mode.bits() as mode_t, - atflag.bits() as libc::c_int, - ) - })?; - - Errno::result(res).map(drop) -} - -/// Change the access and modification times of a file. -/// -/// `utimes(path, times)` is identical to -/// `utimensat(None, path, times, UtimensatFlags::FollowSymlink)`. The former -/// is a deprecated API so prefer using the latter if the platforms you care -/// about support it. -/// -/// # References -/// -/// [utimes(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimes.html). -pub fn utimes<P: ?Sized + NixPath>( - path: &P, - atime: &TimeVal, - mtime: &TimeVal, -) -> Result<()> { - let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()]; - let res = path.with_nix_path(|cstr| unsafe { - libc::utimes(cstr.as_ptr(), ×[0]) - })?; - - Errno::result(res).map(drop) -} - -/// Change the access and modification times of a file without following symlinks. -/// -/// `lutimes(path, times)` is identical to -/// `utimensat(None, path, times, UtimensatFlags::NoFollowSymlink)`. The former -/// is a deprecated API so prefer using the latter if the platforms you care -/// about support it. -/// -/// # References -/// -/// [lutimes(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/lutimes.html). -#[cfg(any( - target_os = "linux", - target_os = "haiku", - target_os = "ios", - target_os = "macos", - target_os = "freebsd", - target_os = "netbsd" -))] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub fn lutimes<P: ?Sized + NixPath>( - path: &P, - atime: &TimeVal, - mtime: &TimeVal, -) -> Result<()> { - let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()]; - let res = path.with_nix_path(|cstr| unsafe { - libc::lutimes(cstr.as_ptr(), ×[0]) - })?; - - Errno::result(res).map(drop) -} - -/// Change the access and modification times of the file specified by a file descriptor. -/// -/// # References -/// -/// [futimens(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html). -#[inline] -pub fn futimens(fd: RawFd, atime: &TimeSpec, mtime: &TimeSpec) -> Result<()> { - let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()]; - let res = unsafe { libc::futimens(fd, ×[0]) }; - - Errno::result(res).map(drop) -} - -/// Flags for `utimensat` function. -// TODO: replace with fcntl::AtFlags -#[derive(Clone, Copy, Debug)] -pub enum UtimensatFlags { - FollowSymlink, - NoFollowSymlink, -} - -/// Change the access and modification times of a file. -/// -/// The file to be changed is determined relative to the directory associated -/// with the file descriptor `dirfd` or the current working directory -/// if `dirfd` is `None`. -/// -/// If `flag` is `UtimensatFlags::NoFollowSymlink` and `path` names a symbolic link, -/// then the mode of the symbolic link is changed. -/// -/// `utimensat(None, path, times, UtimensatFlags::FollowSymlink)` is identical to -/// `utimes(path, times)`. The latter is a deprecated API so prefer using the -/// former if the platforms you care about support it. -/// -/// # References -/// -/// [utimensat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimens.html). -#[cfg(not(target_os = "redox"))] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub fn utimensat<P: ?Sized + NixPath>( - dirfd: Option<RawFd>, - path: &P, - atime: &TimeSpec, - mtime: &TimeSpec, - flag: UtimensatFlags, -) -> Result<()> { - let atflag = match flag { - UtimensatFlags::FollowSymlink => AtFlags::empty(), - UtimensatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW, - }; - let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()]; - let res = path.with_nix_path(|cstr| unsafe { - libc::utimensat( - at_rawfd(dirfd), - cstr.as_ptr(), - ×[0], - atflag.bits() as libc::c_int, - ) - })?; - - Errno::result(res).map(drop) -} - -#[cfg(not(target_os = "redox"))] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub fn mkdirat<P: ?Sized + NixPath>( - fd: RawFd, - path: &P, - mode: Mode, -) -> Result<()> { - let res = path.with_nix_path(|cstr| unsafe { - libc::mkdirat(fd, cstr.as_ptr(), mode.bits() as mode_t) - })?; - - Errno::result(res).map(drop) -} diff --git a/vendor/nix/src/sys/statfs.rs b/vendor/nix/src/sys/statfs.rs deleted file mode 100644 index 9be8ca666..000000000 --- a/vendor/nix/src/sys/statfs.rs +++ /dev/null @@ -1,853 +0,0 @@ -//! Get filesystem statistics, non-portably -//! -//! See [`statvfs`](crate::sys::statvfs) for a portable alternative. -#[cfg(not(any(target_os = "linux", target_os = "android")))] -use std::ffi::CStr; -use std::fmt::{self, Debug}; -use std::mem; -use std::os::unix::io::AsRawFd; - -use cfg_if::cfg_if; - -#[cfg(all( - feature = "mount", - any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ) -))] -use crate::mount::MntFlags; -#[cfg(target_os = "linux")] -use crate::sys::statvfs::FsFlags; -use crate::{errno::Errno, NixPath, Result}; - -/// Identifies a mounted file system -#[cfg(target_os = "android")] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub type fsid_t = libc::__fsid_t; -/// Identifies a mounted file system -#[cfg(not(target_os = "android"))] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub type fsid_t = libc::fsid_t; - -cfg_if! { - if #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] { - type type_of_statfs = libc::statfs64; - const LIBC_FSTATFS: unsafe extern fn - (fd: libc::c_int, buf: *mut type_of_statfs) -> libc::c_int - = libc::fstatfs64; - const LIBC_STATFS: unsafe extern fn - (path: *const libc::c_char, buf: *mut type_of_statfs) -> libc::c_int - = libc::statfs64; - } else { - type type_of_statfs = libc::statfs; - const LIBC_FSTATFS: unsafe extern fn - (fd: libc::c_int, buf: *mut type_of_statfs) -> libc::c_int - = libc::fstatfs; - const LIBC_STATFS: unsafe extern fn - (path: *const libc::c_char, buf: *mut type_of_statfs) -> libc::c_int - = libc::statfs; - } -} - -/// Describes a mounted file system -#[derive(Clone, Copy)] -#[repr(transparent)] -pub struct Statfs(type_of_statfs); - -#[cfg(target_os = "freebsd")] -type fs_type_t = u32; -#[cfg(target_os = "android")] -type fs_type_t = libc::c_ulong; -#[cfg(all(target_os = "linux", target_arch = "s390x"))] -type fs_type_t = libc::c_uint; -#[cfg(all(target_os = "linux", target_env = "musl"))] -type fs_type_t = libc::c_ulong; -#[cfg(all(target_os = "linux", target_env = "uclibc"))] -type fs_type_t = libc::c_int; -#[cfg(all( - target_os = "linux", - not(any( - target_arch = "s390x", - target_env = "musl", - target_env = "uclibc" - )) -))] -type fs_type_t = libc::__fsword_t; - -/// Describes the file system type as known by the operating system. -#[cfg(any( - target_os = "freebsd", - target_os = "android", - all(target_os = "linux", target_arch = "s390x"), - all(target_os = "linux", target_env = "musl"), - all( - target_os = "linux", - not(any(target_arch = "s390x", target_env = "musl")) - ), -))] -#[derive(Eq, Copy, Clone, PartialEq, Debug)] -pub struct FsType(pub fs_type_t); - -// These constants are defined without documentation in the Linux headers, so we -// can't very well document them here. -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const ADFS_SUPER_MAGIC: FsType = - FsType(libc::ADFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const AFFS_SUPER_MAGIC: FsType = - FsType(libc::AFFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const AFS_SUPER_MAGIC: FsType = FsType(libc::AFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const AUTOFS_SUPER_MAGIC: FsType = - FsType(libc::AUTOFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const BPF_FS_MAGIC: FsType = FsType(libc::BPF_FS_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const BTRFS_SUPER_MAGIC: FsType = - FsType(libc::BTRFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const CGROUP2_SUPER_MAGIC: FsType = - FsType(libc::CGROUP2_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const CGROUP_SUPER_MAGIC: FsType = - FsType(libc::CGROUP_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const CODA_SUPER_MAGIC: FsType = - FsType(libc::CODA_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const CRAMFS_MAGIC: FsType = FsType(libc::CRAMFS_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const DEBUGFS_MAGIC: FsType = FsType(libc::DEBUGFS_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const DEVPTS_SUPER_MAGIC: FsType = - FsType(libc::DEVPTS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const ECRYPTFS_SUPER_MAGIC: FsType = - FsType(libc::ECRYPTFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const EFS_SUPER_MAGIC: FsType = FsType(libc::EFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const EXT2_SUPER_MAGIC: FsType = - FsType(libc::EXT2_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const EXT3_SUPER_MAGIC: FsType = - FsType(libc::EXT3_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const EXT4_SUPER_MAGIC: FsType = - FsType(libc::EXT4_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const F2FS_SUPER_MAGIC: FsType = - FsType(libc::F2FS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const FUSE_SUPER_MAGIC: FsType = - FsType(libc::FUSE_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const FUTEXFS_SUPER_MAGIC: FsType = - FsType(libc::FUTEXFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const HOSTFS_SUPER_MAGIC: FsType = - FsType(libc::HOSTFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const HPFS_SUPER_MAGIC: FsType = - FsType(libc::HPFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const HUGETLBFS_MAGIC: FsType = FsType(libc::HUGETLBFS_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const ISOFS_SUPER_MAGIC: FsType = - FsType(libc::ISOFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const JFFS2_SUPER_MAGIC: FsType = - FsType(libc::JFFS2_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const MINIX2_SUPER_MAGIC2: FsType = - FsType(libc::MINIX2_SUPER_MAGIC2 as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const MINIX2_SUPER_MAGIC: FsType = - FsType(libc::MINIX2_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const MINIX3_SUPER_MAGIC: FsType = - FsType(libc::MINIX3_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const MINIX_SUPER_MAGIC2: FsType = - FsType(libc::MINIX_SUPER_MAGIC2 as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const MINIX_SUPER_MAGIC: FsType = - FsType(libc::MINIX_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const MSDOS_SUPER_MAGIC: FsType = - FsType(libc::MSDOS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const NCP_SUPER_MAGIC: FsType = FsType(libc::NCP_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const NFS_SUPER_MAGIC: FsType = FsType(libc::NFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const NILFS_SUPER_MAGIC: FsType = - FsType(libc::NILFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const OCFS2_SUPER_MAGIC: FsType = - FsType(libc::OCFS2_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const OPENPROM_SUPER_MAGIC: FsType = - FsType(libc::OPENPROM_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const OVERLAYFS_SUPER_MAGIC: FsType = - FsType(libc::OVERLAYFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const PROC_SUPER_MAGIC: FsType = - FsType(libc::PROC_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const QNX4_SUPER_MAGIC: FsType = - FsType(libc::QNX4_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const QNX6_SUPER_MAGIC: FsType = - FsType(libc::QNX6_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const RDTGROUP_SUPER_MAGIC: FsType = - FsType(libc::RDTGROUP_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const REISERFS_SUPER_MAGIC: FsType = - FsType(libc::REISERFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const SECURITYFS_MAGIC: FsType = - FsType(libc::SECURITYFS_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const SELINUX_MAGIC: FsType = FsType(libc::SELINUX_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const SMACK_MAGIC: FsType = FsType(libc::SMACK_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const SMB_SUPER_MAGIC: FsType = FsType(libc::SMB_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const SYSFS_MAGIC: FsType = FsType(libc::SYSFS_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const TMPFS_MAGIC: FsType = FsType(libc::TMPFS_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const TRACEFS_MAGIC: FsType = FsType(libc::TRACEFS_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const UDF_SUPER_MAGIC: FsType = FsType(libc::UDF_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const USBDEVICE_SUPER_MAGIC: FsType = - FsType(libc::USBDEVICE_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const XENFS_SUPER_MAGIC: FsType = - FsType(libc::XENFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(target_os = "linux", target_os = "android"))] -#[allow(missing_docs)] -pub const NSFS_MAGIC: FsType = FsType(libc::NSFS_MAGIC as fs_type_t); -#[cfg(all( - any(target_os = "linux", target_os = "android"), - not(target_env = "musl") -))] -#[allow(missing_docs)] -pub const XFS_SUPER_MAGIC: FsType = FsType(libc::XFS_SUPER_MAGIC as fs_type_t); - -impl Statfs { - /// Magic code defining system type - #[cfg(not(any( - target_os = "openbsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos" - )))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn filesystem_type(&self) -> FsType { - FsType(self.0.f_type) - } - - /// Magic code defining system type - #[cfg(not(any(target_os = "linux", target_os = "android")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn filesystem_type_name(&self) -> &str { - let c_str = unsafe { CStr::from_ptr(self.0.f_fstypename.as_ptr()) }; - c_str.to_str().unwrap() - } - - /// Optimal transfer block size - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn optimal_transfer_size(&self) -> i32 { - self.0.f_iosize - } - - /// Optimal transfer block size - #[cfg(target_os = "openbsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn optimal_transfer_size(&self) -> u32 { - self.0.f_iosize - } - - /// Optimal transfer block size - #[cfg(all(target_os = "linux", target_arch = "s390x"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn optimal_transfer_size(&self) -> u32 { - self.0.f_bsize - } - - /// Optimal transfer block size - #[cfg(any( - target_os = "android", - all(target_os = "linux", target_env = "musl") - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn optimal_transfer_size(&self) -> libc::c_ulong { - self.0.f_bsize - } - - /// Optimal transfer block size - #[cfg(all( - target_os = "linux", - not(any( - target_arch = "s390x", - target_env = "musl", - target_env = "uclibc" - )) - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn optimal_transfer_size(&self) -> libc::__fsword_t { - self.0.f_bsize - } - - /// Optimal transfer block size - #[cfg(all(target_os = "linux", target_env = "uclibc"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn optimal_transfer_size(&self) -> libc::c_int { - self.0.f_bsize - } - - /// Optimal transfer block size - #[cfg(target_os = "dragonfly")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn optimal_transfer_size(&self) -> libc::c_long { - self.0.f_iosize - } - - /// Optimal transfer block size - #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn optimal_transfer_size(&self) -> u64 { - self.0.f_iosize - } - - /// Size of a block - #[cfg(any(target_os = "ios", target_os = "macos", target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn block_size(&self) -> u32 { - self.0.f_bsize - } - - /// Size of a block - // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471 - #[cfg(all(target_os = "linux", target_arch = "s390x"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn block_size(&self) -> u32 { - self.0.f_bsize - } - - /// Size of a block - // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471 - #[cfg(all(target_os = "linux", target_env = "musl"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn block_size(&self) -> libc::c_ulong { - self.0.f_bsize - } - - /// Size of a block - // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471 - #[cfg(all(target_os = "linux", target_env = "uclibc"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn block_size(&self) -> libc::c_int { - self.0.f_bsize - } - - /// Size of a block - // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471 - #[cfg(all( - target_os = "linux", - not(any( - target_arch = "s390x", - target_env = "musl", - target_env = "uclibc" - )) - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn block_size(&self) -> libc::__fsword_t { - self.0.f_bsize - } - - /// Size of a block - #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn block_size(&self) -> u64 { - self.0.f_bsize - } - - /// Size of a block - #[cfg(target_os = "android")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn block_size(&self) -> libc::c_ulong { - self.0.f_bsize - } - - /// Size of a block - #[cfg(target_os = "dragonfly")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn block_size(&self) -> libc::c_long { - self.0.f_bsize - } - - /// Get the mount flags - #[cfg(all( - feature = "mount", - any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ) - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - #[allow(clippy::unnecessary_cast)] // Not unnecessary on all arches - pub fn flags(&self) -> MntFlags { - MntFlags::from_bits_truncate(self.0.f_flags as i32) - } - - /// Get the mount flags - // The f_flags field exists on Android and Fuchsia too, but without man - // pages I can't tell if it can be cast to FsFlags. - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn flags(&self) -> FsFlags { - FsFlags::from_bits_truncate(self.0.f_flags as libc::c_ulong) - } - - /// Maximum length of filenames - #[cfg(any(target_os = "freebsd", target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn maximum_name_length(&self) -> u32 { - self.0.f_namemax - } - - /// Maximum length of filenames - #[cfg(all(target_os = "linux", target_arch = "s390x"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn maximum_name_length(&self) -> u32 { - self.0.f_namelen - } - - /// Maximum length of filenames - #[cfg(all(target_os = "linux", target_env = "musl"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn maximum_name_length(&self) -> libc::c_ulong { - self.0.f_namelen - } - - /// Maximum length of filenames - #[cfg(all(target_os = "linux", target_env = "uclibc"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn maximum_name_length(&self) -> libc::c_int { - self.0.f_namelen - } - - /// Maximum length of filenames - #[cfg(all( - target_os = "linux", - not(any( - target_arch = "s390x", - target_env = "musl", - target_env = "uclibc" - )) - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn maximum_name_length(&self) -> libc::__fsword_t { - self.0.f_namelen - } - - /// Maximum length of filenames - #[cfg(target_os = "android")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn maximum_name_length(&self) -> libc::c_ulong { - self.0.f_namelen - } - - /// Total data blocks in filesystem - #[cfg(any( - target_os = "ios", - target_os = "macos", - target_os = "android", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "openbsd", - target_os = "linux", - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn blocks(&self) -> u64 { - self.0.f_blocks - } - - /// Total data blocks in filesystem - #[cfg(target_os = "dragonfly")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn blocks(&self) -> libc::c_long { - self.0.f_blocks - } - - /// Total data blocks in filesystem - #[cfg(target_os = "emscripten")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn blocks(&self) -> u32 { - self.0.f_blocks - } - - /// Free blocks in filesystem - #[cfg(any( - target_os = "ios", - target_os = "macos", - target_os = "android", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "openbsd", - target_os = "linux", - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn blocks_free(&self) -> u64 { - self.0.f_bfree - } - - /// Free blocks in filesystem - #[cfg(target_os = "dragonfly")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn blocks_free(&self) -> libc::c_long { - self.0.f_bfree - } - - /// Free blocks in filesystem - #[cfg(target_os = "emscripten")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn blocks_free(&self) -> u32 { - self.0.f_bfree - } - - /// Free blocks available to unprivileged user - #[cfg(any( - target_os = "ios", - target_os = "macos", - target_os = "android", - target_os = "fuchsia", - target_os = "linux", - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn blocks_available(&self) -> u64 { - self.0.f_bavail - } - - /// Free blocks available to unprivileged user - #[cfg(target_os = "dragonfly")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn blocks_available(&self) -> libc::c_long { - self.0.f_bavail - } - - /// Free blocks available to unprivileged user - #[cfg(any(target_os = "freebsd", target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn blocks_available(&self) -> i64 { - self.0.f_bavail - } - - /// Free blocks available to unprivileged user - #[cfg(target_os = "emscripten")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn blocks_available(&self) -> u32 { - self.0.f_bavail - } - - /// Total file nodes in filesystem - #[cfg(any( - target_os = "ios", - target_os = "macos", - target_os = "android", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "openbsd", - target_os = "linux", - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn files(&self) -> u64 { - self.0.f_files - } - - /// Total file nodes in filesystem - #[cfg(target_os = "dragonfly")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn files(&self) -> libc::c_long { - self.0.f_files - } - - /// Total file nodes in filesystem - #[cfg(target_os = "emscripten")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn files(&self) -> u32 { - self.0.f_files - } - - /// Free file nodes in filesystem - #[cfg(any( - target_os = "ios", - target_os = "macos", - target_os = "android", - target_os = "fuchsia", - target_os = "openbsd", - target_os = "linux", - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn files_free(&self) -> u64 { - self.0.f_ffree - } - - /// Free file nodes in filesystem - #[cfg(target_os = "dragonfly")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn files_free(&self) -> libc::c_long { - self.0.f_ffree - } - - /// Free file nodes in filesystem - #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn files_free(&self) -> i64 { - self.0.f_ffree - } - - /// Free file nodes in filesystem - #[cfg(target_os = "emscripten")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn files_free(&self) -> u32 { - self.0.f_ffree - } - - /// Filesystem ID - pub fn filesystem_id(&self) -> fsid_t { - self.0.f_fsid - } -} - -impl Debug for Statfs { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut ds = f.debug_struct("Statfs"); - ds.field("optimal_transfer_size", &self.optimal_transfer_size()); - ds.field("block_size", &self.block_size()); - ds.field("blocks", &self.blocks()); - ds.field("blocks_free", &self.blocks_free()); - ds.field("blocks_available", &self.blocks_available()); - ds.field("files", &self.files()); - ds.field("files_free", &self.files_free()); - ds.field("filesystem_id", &self.filesystem_id()); - #[cfg(all( - feature = "mount", - any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ) - ))] - ds.field("flags", &self.flags()); - ds.finish() - } -} - -/// Describes a mounted file system. -/// -/// The result is OS-dependent. For a portable alternative, see -/// [`statvfs`](crate::sys::statvfs::statvfs). -/// -/// # Arguments -/// -/// `path` - Path to any file within the file system to describe -pub fn statfs<P: ?Sized + NixPath>(path: &P) -> Result<Statfs> { - unsafe { - let mut stat = mem::MaybeUninit::<type_of_statfs>::uninit(); - let res = path.with_nix_path(|path| { - LIBC_STATFS(path.as_ptr(), stat.as_mut_ptr()) - })?; - Errno::result(res).map(|_| Statfs(stat.assume_init())) - } -} - -/// Describes a mounted file system. -/// -/// The result is OS-dependent. For a portable alternative, see -/// [`fstatvfs`](crate::sys::statvfs::fstatvfs). -/// -/// # Arguments -/// -/// `fd` - File descriptor of any open file within the file system to describe -pub fn fstatfs<T: AsRawFd>(fd: &T) -> Result<Statfs> { - unsafe { - let mut stat = mem::MaybeUninit::<type_of_statfs>::uninit(); - Errno::result(LIBC_FSTATFS(fd.as_raw_fd(), stat.as_mut_ptr())) - .map(|_| Statfs(stat.assume_init())) - } -} - -#[cfg(test)] -mod test { - use std::fs::File; - - use crate::sys::statfs::*; - use crate::sys::statvfs::*; - use std::path::Path; - - #[test] - fn statfs_call() { - check_statfs("/tmp"); - check_statfs("/dev"); - check_statfs("/run"); - check_statfs("/"); - } - - #[test] - fn fstatfs_call() { - check_fstatfs("/tmp"); - check_fstatfs("/dev"); - check_fstatfs("/run"); - check_fstatfs("/"); - } - - fn check_fstatfs(path: &str) { - if !Path::new(path).exists() { - return; - } - let vfs = statvfs(path.as_bytes()).unwrap(); - let file = File::open(path).unwrap(); - let fs = fstatfs(&file).unwrap(); - assert_fs_equals(fs, vfs); - } - - fn check_statfs(path: &str) { - if !Path::new(path).exists() { - return; - } - let vfs = statvfs(path.as_bytes()).unwrap(); - let fs = statfs(path.as_bytes()).unwrap(); - assert_fs_equals(fs, vfs); - } - - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - fn assert_fs_equals(fs: Statfs, vfs: Statvfs) { - assert_eq!(fs.files() as u64, vfs.files() as u64); - assert_eq!(fs.blocks() as u64, vfs.blocks() as u64); - assert_eq!(fs.block_size() as u64, vfs.fragment_size() as u64); - } - - // This test is ignored because files_free/blocks_free can change after statvfs call and before - // statfs call. - #[test] - #[ignore] - fn statfs_call_strict() { - check_statfs_strict("/tmp"); - check_statfs_strict("/dev"); - check_statfs_strict("/run"); - check_statfs_strict("/"); - } - - // This test is ignored because files_free/blocks_free can change after statvfs call and before - // fstatfs call. - #[test] - #[ignore] - fn fstatfs_call_strict() { - check_fstatfs_strict("/tmp"); - check_fstatfs_strict("/dev"); - check_fstatfs_strict("/run"); - check_fstatfs_strict("/"); - } - - fn check_fstatfs_strict(path: &str) { - if !Path::new(path).exists() { - return; - } - let vfs = statvfs(path.as_bytes()); - let file = File::open(path).unwrap(); - let fs = fstatfs(&file); - assert_fs_equals_strict(fs.unwrap(), vfs.unwrap()) - } - - fn check_statfs_strict(path: &str) { - if !Path::new(path).exists() { - return; - } - let vfs = statvfs(path.as_bytes()); - let fs = statfs(path.as_bytes()); - assert_fs_equals_strict(fs.unwrap(), vfs.unwrap()) - } - - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - fn assert_fs_equals_strict(fs: Statfs, vfs: Statvfs) { - assert_eq!(fs.files_free() as u64, vfs.files_free() as u64); - assert_eq!(fs.blocks_free() as u64, vfs.blocks_free() as u64); - assert_eq!(fs.blocks_available() as u64, vfs.blocks_available() as u64); - assert_eq!(fs.files() as u64, vfs.files() as u64); - assert_eq!(fs.blocks() as u64, vfs.blocks() as u64); - assert_eq!(fs.block_size() as u64, vfs.fragment_size() as u64); - } -} diff --git a/vendor/nix/src/sys/statvfs.rs b/vendor/nix/src/sys/statvfs.rs deleted file mode 100644 index 8de369f42..000000000 --- a/vendor/nix/src/sys/statvfs.rs +++ /dev/null @@ -1,173 +0,0 @@ -//! Get filesystem statistics -//! -//! See [the man pages](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fstatvfs.html) -//! for more details. -use std::mem; -use std::os::unix::io::AsRawFd; - -use libc::{self, c_ulong}; - -use crate::{errno::Errno, NixPath, Result}; - -#[cfg(not(target_os = "redox"))] -libc_bitflags!( - /// File system mount Flags - #[repr(C)] - #[derive(Default)] - pub struct FsFlags: c_ulong { - /// Read Only - #[cfg(not(target_os = "haiku"))] - ST_RDONLY; - /// Do not allow the set-uid bits to have an effect - #[cfg(not(target_os = "haiku"))] - ST_NOSUID; - /// Do not interpret character or block-special devices - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ST_NODEV; - /// Do not allow execution of binaries on the filesystem - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ST_NOEXEC; - /// All IO should be done synchronously - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ST_SYNCHRONOUS; - /// Allow mandatory locks on the filesystem - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ST_MANDLOCK; - /// Write on file/directory/symlink - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - ST_WRITE; - /// Append-only file - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - ST_APPEND; - /// Immutable file - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - ST_IMMUTABLE; - /// Do not update access times on files - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ST_NOATIME; - /// Do not update access times on files - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ST_NODIRATIME; - /// Update access time relative to modify/change time - #[cfg(any(target_os = "android", all(target_os = "linux", not(target_env = "musl"))))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ST_RELATIME; - } -); - -/// Wrapper around the POSIX `statvfs` struct -/// -/// For more information see the [`statvfs(3)` man pages](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_statvfs.h.html). -#[repr(transparent)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct Statvfs(libc::statvfs); - -impl Statvfs { - /// get the file system block size - pub fn block_size(&self) -> c_ulong { - self.0.f_bsize - } - - /// Get the fundamental file system block size - pub fn fragment_size(&self) -> c_ulong { - self.0.f_frsize - } - - /// Get the number of blocks. - /// - /// Units are in units of `fragment_size()` - pub fn blocks(&self) -> libc::fsblkcnt_t { - self.0.f_blocks - } - - /// Get the number of free blocks in the file system - pub fn blocks_free(&self) -> libc::fsblkcnt_t { - self.0.f_bfree - } - - /// Get the number of free blocks for unprivileged users - pub fn blocks_available(&self) -> libc::fsblkcnt_t { - self.0.f_bavail - } - - /// Get the total number of file inodes - pub fn files(&self) -> libc::fsfilcnt_t { - self.0.f_files - } - - /// Get the number of free file inodes - pub fn files_free(&self) -> libc::fsfilcnt_t { - self.0.f_ffree - } - - /// Get the number of free file inodes for unprivileged users - pub fn files_available(&self) -> libc::fsfilcnt_t { - self.0.f_favail - } - - /// Get the file system id - pub fn filesystem_id(&self) -> c_ulong { - self.0.f_fsid - } - - /// Get the mount flags - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn flags(&self) -> FsFlags { - FsFlags::from_bits_truncate(self.0.f_flag) - } - - /// Get the maximum filename length - pub fn name_max(&self) -> c_ulong { - self.0.f_namemax - } -} - -/// Return a `Statvfs` object with information about the `path` -pub fn statvfs<P: ?Sized + NixPath>(path: &P) -> Result<Statvfs> { - unsafe { - Errno::clear(); - let mut stat = mem::MaybeUninit::<libc::statvfs>::uninit(); - let res = path.with_nix_path(|path| { - libc::statvfs(path.as_ptr(), stat.as_mut_ptr()) - })?; - - Errno::result(res).map(|_| Statvfs(stat.assume_init())) - } -} - -/// Return a `Statvfs` object with information about `fd` -pub fn fstatvfs<T: AsRawFd>(fd: &T) -> Result<Statvfs> { - unsafe { - Errno::clear(); - let mut stat = mem::MaybeUninit::<libc::statvfs>::uninit(); - Errno::result(libc::fstatvfs(fd.as_raw_fd(), stat.as_mut_ptr())) - .map(|_| Statvfs(stat.assume_init())) - } -} - -#[cfg(test)] -mod test { - use crate::sys::statvfs::*; - use std::fs::File; - - #[test] - fn statvfs_call() { - statvfs(&b"/"[..]).unwrap(); - } - - #[test] - fn fstatvfs_call() { - let root = File::open("/").unwrap(); - fstatvfs(&root).unwrap(); - } -} diff --git a/vendor/nix/src/sys/sysinfo.rs b/vendor/nix/src/sys/sysinfo.rs deleted file mode 100644 index e8aa00b00..000000000 --- a/vendor/nix/src/sys/sysinfo.rs +++ /dev/null @@ -1,83 +0,0 @@ -use libc::{self, SI_LOAD_SHIFT}; -use std::time::Duration; -use std::{cmp, mem}; - -use crate::errno::Errno; -use crate::Result; - -/// System info structure returned by `sysinfo`. -#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)] -#[repr(transparent)] -pub struct SysInfo(libc::sysinfo); - -// The fields are c_ulong on 32-bit linux, u64 on 64-bit linux; x32's ulong is u32 -#[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] -type mem_blocks_t = u64; -#[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] -type mem_blocks_t = libc::c_ulong; - -impl SysInfo { - /// Returns the load average tuple. - /// - /// The returned values represent the load average over time intervals of - /// 1, 5, and 15 minutes, respectively. - pub fn load_average(&self) -> (f64, f64, f64) { - ( - self.0.loads[0] as f64 / (1 << SI_LOAD_SHIFT) as f64, - self.0.loads[1] as f64 / (1 << SI_LOAD_SHIFT) as f64, - self.0.loads[2] as f64 / (1 << SI_LOAD_SHIFT) as f64, - ) - } - - /// Returns the time since system boot. - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - pub fn uptime(&self) -> Duration { - // Truncate negative values to 0 - Duration::from_secs(cmp::max(self.0.uptime, 0) as u64) - } - - /// Current number of processes. - pub fn process_count(&self) -> u16 { - self.0.procs - } - - /// Returns the amount of swap memory in Bytes. - pub fn swap_total(&self) -> u64 { - self.scale_mem(self.0.totalswap) - } - - /// Returns the amount of unused swap memory in Bytes. - pub fn swap_free(&self) -> u64 { - self.scale_mem(self.0.freeswap) - } - - /// Returns the total amount of installed RAM in Bytes. - pub fn ram_total(&self) -> u64 { - self.scale_mem(self.0.totalram) - } - - /// Returns the amount of completely unused RAM in Bytes. - /// - /// "Unused" in this context means that the RAM in neither actively used by - /// programs, nor by the operating system as disk cache or buffer. It is - /// "wasted" RAM since it currently serves no purpose. - pub fn ram_unused(&self) -> u64 { - self.scale_mem(self.0.freeram) - } - - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - fn scale_mem(&self, units: mem_blocks_t) -> u64 { - units as u64 * self.0.mem_unit as u64 - } -} - -/// Returns system information. -/// -/// [See `sysinfo(2)`](https://man7.org/linux/man-pages/man2/sysinfo.2.html). -pub fn sysinfo() -> Result<SysInfo> { - let mut info = mem::MaybeUninit::uninit(); - let res = unsafe { libc::sysinfo(info.as_mut_ptr()) }; - Errno::result(res).map(|_| unsafe { SysInfo(info.assume_init()) }) -} diff --git a/vendor/nix/src/sys/termios.rs b/vendor/nix/src/sys/termios.rs deleted file mode 100644 index fba2cd826..000000000 --- a/vendor/nix/src/sys/termios.rs +++ /dev/null @@ -1,1227 +0,0 @@ -//! An interface for controlling asynchronous communication ports -//! -//! This interface provides a safe wrapper around the termios subsystem defined by POSIX. The -//! underlying types are all implemented in libc for most platforms and either wrapped in safer -//! types here or exported directly. -//! -//! If you are unfamiliar with the `termios` API, you should first read the -//! [API documentation](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/termios.h.html) and -//! then come back to understand how `nix` safely wraps it. -//! -//! It should be noted that this API incurs some runtime overhead above the base `libc` definitions. -//! As this interface is not used with high-bandwidth information, this should be fine in most -//! cases. The primary cost when using this API is that the `Termios` datatype here duplicates the -//! standard fields of the underlying `termios` struct and uses safe type wrappers for those fields. -//! This means that when crossing the FFI interface to the underlying C library, data is first -//! copied into the underlying `termios` struct, then the operation is done, and the data is copied -//! back (with additional sanity checking) into the safe wrapper types. The `termios` struct is -//! relatively small across all platforms (on the order of 32-64 bytes). -//! -//! The following examples highlight some of the API use cases such that users coming from using C -//! or reading the standard documentation will understand how to use the safe API exposed here. -//! -//! Example disabling processing of the end-of-file control character: -//! -//! ``` -//! # use self::nix::sys::termios::SpecialCharacterIndices::VEOF; -//! # use self::nix::sys::termios::{_POSIX_VDISABLE, Termios}; -//! # let mut termios: Termios = unsafe { std::mem::zeroed() }; -//! termios.control_chars[VEOF as usize] = _POSIX_VDISABLE; -//! ``` -//! -//! The flags within `Termios` are defined as bitfields using the `bitflags` crate. This provides -//! an interface for working with bitfields that is similar to working with the raw unsigned -//! integer types but offers type safety because of the internal checking that values will always -//! be a valid combination of the defined flags. -//! -//! An example showing some of the basic operations for interacting with the control flags: -//! -//! ``` -//! # use self::nix::sys::termios::{ControlFlags, Termios}; -//! # let mut termios: Termios = unsafe { std::mem::zeroed() }; -//! termios.control_flags & ControlFlags::CSIZE == ControlFlags::CS5; -//! termios.control_flags |= ControlFlags::CS5; -//! ``` -//! -//! # Baud rates -//! -//! This API is not consistent across platforms when it comes to `BaudRate`: Android and Linux both -//! only support the rates specified by the `BaudRate` enum through their termios API while the BSDs -//! support arbitrary baud rates as the values of the `BaudRate` enum constants are the same integer -//! value of the constant (`B9600` == `9600`). Therefore the `nix::termios` API uses the following -//! conventions: -//! -//! * `cfgetispeed()` - Returns `u32` on BSDs, `BaudRate` on Android/Linux -//! * `cfgetospeed()` - Returns `u32` on BSDs, `BaudRate` on Android/Linux -//! * `cfsetispeed()` - Takes `u32` or `BaudRate` on BSDs, `BaudRate` on Android/Linux -//! * `cfsetospeed()` - Takes `u32` or `BaudRate` on BSDs, `BaudRate` on Android/Linux -//! * `cfsetspeed()` - Takes `u32` or `BaudRate` on BSDs, `BaudRate` on Android/Linux -//! -//! The most common use case of specifying a baud rate using the enum will work the same across -//! platforms: -//! -//! ```rust -//! # use nix::sys::termios::{BaudRate, cfsetispeed, cfsetospeed, cfsetspeed, Termios}; -//! # fn main() { -//! # let mut t: Termios = unsafe { std::mem::zeroed() }; -//! cfsetispeed(&mut t, BaudRate::B9600).unwrap(); -//! cfsetospeed(&mut t, BaudRate::B9600).unwrap(); -//! cfsetspeed(&mut t, BaudRate::B9600).unwrap(); -//! # } -//! ``` -//! -//! Additionally round-tripping baud rates is consistent across platforms: -//! -//! ```rust -//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetispeed, cfsetspeed, Termios}; -//! # fn main() { -//! # let mut t: Termios = unsafe { std::mem::zeroed() }; -//! # cfsetspeed(&mut t, BaudRate::B9600).unwrap(); -//! let speed = cfgetispeed(&t); -//! assert_eq!(speed, cfgetospeed(&t)); -//! cfsetispeed(&mut t, speed).unwrap(); -//! # } -//! ``` -//! -//! On non-BSDs, `cfgetispeed()` and `cfgetospeed()` both return a `BaudRate`: -//! -#![cfg_attr( - any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ), - doc = " ```rust,ignore" -)] -#![cfg_attr( - not(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - )), - doc = " ```rust" -)] -//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetspeed, Termios}; -//! # fn main() { -//! # let mut t: Termios = unsafe { std::mem::zeroed() }; -//! # cfsetspeed(&mut t, BaudRate::B9600); -//! assert_eq!(cfgetispeed(&t), BaudRate::B9600); -//! assert_eq!(cfgetospeed(&t), BaudRate::B9600); -//! # } -//! ``` -//! -//! But on the BSDs, `cfgetispeed()` and `cfgetospeed()` both return `u32`s: -//! -#![cfg_attr( - any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ), - doc = " ```rust" -)] -#![cfg_attr( - not(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - )), - doc = " ```rust,ignore" -)] -//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetspeed, Termios}; -//! # fn main() { -//! # let mut t: Termios = unsafe { std::mem::zeroed() }; -//! # cfsetspeed(&mut t, 9600u32); -//! assert_eq!(cfgetispeed(&t), 9600u32); -//! assert_eq!(cfgetospeed(&t), 9600u32); -//! # } -//! ``` -//! -//! It's trivial to convert from a `BaudRate` to a `u32` on BSDs: -//! -#![cfg_attr( - any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ), - doc = " ```rust" -)] -#![cfg_attr( - not(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - )), - doc = " ```rust,ignore" -)] -//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfsetspeed, Termios}; -//! # fn main() { -//! # let mut t: Termios = unsafe { std::mem::zeroed() }; -//! # cfsetspeed(&mut t, 9600u32); -//! assert_eq!(cfgetispeed(&t), BaudRate::B9600.into()); -//! assert_eq!(u32::from(BaudRate::B9600), 9600u32); -//! # } -//! ``` -//! -//! And on BSDs you can specify arbitrary baud rates (**note** this depends on hardware support) -//! by specifying baud rates directly using `u32`s: -//! -#![cfg_attr( - any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ), - doc = " ```rust" -)] -#![cfg_attr( - not(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - )), - doc = " ```rust,ignore" -)] -//! # use nix::sys::termios::{cfsetispeed, cfsetospeed, cfsetspeed, Termios}; -//! # fn main() { -//! # let mut t: Termios = unsafe { std::mem::zeroed() }; -//! cfsetispeed(&mut t, 9600u32); -//! cfsetospeed(&mut t, 9600u32); -//! cfsetspeed(&mut t, 9600u32); -//! # } -//! ``` -use crate::errno::Errno; -use crate::Result; -use cfg_if::cfg_if; -use libc::{self, c_int, tcflag_t}; -use std::cell::{Ref, RefCell}; -use std::convert::From; -use std::mem; -use std::os::unix::io::RawFd; - -#[cfg(feature = "process")] -use crate::unistd::Pid; - -/// Stores settings for the termios API -/// -/// This is a wrapper around the `libc::termios` struct that provides a safe interface for the -/// standard fields. The only safe way to obtain an instance of this struct is to extract it from -/// an open port using `tcgetattr()`. -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct Termios { - inner: RefCell<libc::termios>, - /// Input mode flags (see `termios.c_iflag` documentation) - pub input_flags: InputFlags, - /// Output mode flags (see `termios.c_oflag` documentation) - pub output_flags: OutputFlags, - /// Control mode flags (see `termios.c_cflag` documentation) - pub control_flags: ControlFlags, - /// Local mode flags (see `termios.c_lflag` documentation) - pub local_flags: LocalFlags, - /// Control characters (see `termios.c_cc` documentation) - pub control_chars: [libc::cc_t; NCCS], - /// Line discipline (see `termios.c_line` documentation) - #[cfg(any(target_os = "linux", target_os = "android",))] - pub line_discipline: libc::cc_t, - /// Line discipline (see `termios.c_line` documentation) - #[cfg(target_os = "haiku")] - pub line_discipline: libc::c_char, -} - -impl Termios { - /// Exposes an immutable reference to the underlying `libc::termios` data structure. - /// - /// This is not part of `nix`'s public API because it requires additional work to maintain type - /// safety. - pub(crate) fn get_libc_termios(&self) -> Ref<libc::termios> { - { - let mut termios = self.inner.borrow_mut(); - termios.c_iflag = self.input_flags.bits(); - termios.c_oflag = self.output_flags.bits(); - termios.c_cflag = self.control_flags.bits(); - termios.c_lflag = self.local_flags.bits(); - termios.c_cc = self.control_chars; - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "haiku", - ))] - { - termios.c_line = self.line_discipline; - } - } - self.inner.borrow() - } - - /// Exposes the inner `libc::termios` datastore within `Termios`. - /// - /// This is unsafe because if this is used to modify the inner `libc::termios` struct, it will - /// not automatically update the safe wrapper type around it. In this case it should also be - /// paired with a call to `update_wrapper()` so that the wrapper-type and internal - /// representation stay consistent. - pub(crate) unsafe fn get_libc_termios_mut(&mut self) -> *mut libc::termios { - { - let mut termios = self.inner.borrow_mut(); - termios.c_iflag = self.input_flags.bits(); - termios.c_oflag = self.output_flags.bits(); - termios.c_cflag = self.control_flags.bits(); - termios.c_lflag = self.local_flags.bits(); - termios.c_cc = self.control_chars; - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "haiku", - ))] - { - termios.c_line = self.line_discipline; - } - } - self.inner.as_ptr() - } - - /// Updates the wrapper values from the internal `libc::termios` data structure. - pub(crate) fn update_wrapper(&mut self) { - let termios = *self.inner.borrow_mut(); - self.input_flags = InputFlags::from_bits_truncate(termios.c_iflag); - self.output_flags = OutputFlags::from_bits_truncate(termios.c_oflag); - self.control_flags = ControlFlags::from_bits_truncate(termios.c_cflag); - self.local_flags = LocalFlags::from_bits_truncate(termios.c_lflag); - self.control_chars = termios.c_cc; - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "haiku", - ))] - { - self.line_discipline = termios.c_line; - } - } -} - -impl From<libc::termios> for Termios { - fn from(termios: libc::termios) -> Self { - Termios { - inner: RefCell::new(termios), - input_flags: InputFlags::from_bits_truncate(termios.c_iflag), - output_flags: OutputFlags::from_bits_truncate(termios.c_oflag), - control_flags: ControlFlags::from_bits_truncate(termios.c_cflag), - local_flags: LocalFlags::from_bits_truncate(termios.c_lflag), - control_chars: termios.c_cc, - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "haiku", - ))] - line_discipline: termios.c_line, - } - } -} - -impl From<Termios> for libc::termios { - fn from(termios: Termios) -> Self { - termios.inner.into_inner() - } -} - -libc_enum! { - /// Baud rates supported by the system. - /// - /// For the BSDs, arbitrary baud rates can be specified by using `u32`s directly instead of this - /// enum. - /// - /// B0 is special and will disable the port. - #[cfg_attr(all(any(target_os = "haiku"), target_pointer_width = "64"), repr(u8))] - #[cfg_attr(all(any(target_os = "ios", target_os = "macos"), target_pointer_width = "64"), repr(u64))] - #[cfg_attr(not(all(any(target_os = "ios", target_os = "macos", target_os = "haiku"), target_pointer_width = "64")), repr(u32))] - #[non_exhaustive] - pub enum BaudRate { - B0, - B50, - B75, - B110, - B134, - B150, - B200, - B300, - B600, - B1200, - B1800, - B2400, - B4800, - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B7200, - B9600, - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B14400, - B19200, - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B28800, - B38400, - B57600, - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B76800, - B115200, - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B153600, - B230400, - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B307200, - #[cfg(any(target_os = "android", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B460800, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B500000, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B576000, - #[cfg(any(target_os = "android", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B921600, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B1000000, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B1152000, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B1500000, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B2000000, - #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B2500000, - #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B3000000, - #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B3500000, - #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] - #[cfg_attr(docsrs, doc(cfg(all())))] - B4000000, - } - impl TryFrom<libc::speed_t> -} - -#[cfg(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" -))] -impl From<BaudRate> for u32 { - fn from(b: BaudRate) -> u32 { - b as u32 - } -} - -#[cfg(target_os = "haiku")] -impl From<BaudRate> for u8 { - fn from(b: BaudRate) -> u8 { - b as u8 - } -} - -// TODO: Add TCSASOFT, which will require treating this as a bitfield. -libc_enum! { - /// Specify when a port configuration change should occur. - /// - /// Used as an argument to `tcsetattr()` - #[repr(i32)] - #[non_exhaustive] - pub enum SetArg { - /// The change will occur immediately - TCSANOW, - /// The change occurs after all output has been written - TCSADRAIN, - /// Same as `TCSADRAIN`, but will also flush the input buffer - TCSAFLUSH, - } -} - -libc_enum! { - /// Specify a combination of the input and output buffers to flush - /// - /// Used as an argument to `tcflush()`. - #[repr(i32)] - #[non_exhaustive] - pub enum FlushArg { - /// Flush data that was received but not read - TCIFLUSH, - /// Flush data written but not transmitted - TCOFLUSH, - /// Flush both received data not read and written data not transmitted - TCIOFLUSH, - } -} - -libc_enum! { - /// Specify how transmission flow should be altered - /// - /// Used as an argument to `tcflow()`. - #[repr(i32)] - #[non_exhaustive] - pub enum FlowArg { - /// Suspend transmission - TCOOFF, - /// Resume transmission - TCOON, - /// Transmit a STOP character, which should disable a connected terminal device - TCIOFF, - /// Transmit a START character, which should re-enable a connected terminal device - TCION, - } -} - -// TODO: Make this usable directly as a slice index. -#[cfg(not(target_os = "haiku"))] -libc_enum! { - /// Indices into the `termios.c_cc` array for special characters. - #[repr(usize)] - #[non_exhaustive] - pub enum SpecialCharacterIndices { - VDISCARD, - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - VDSUSP, - VEOF, - VEOL, - VEOL2, - VERASE, - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - VERASE2, - VINTR, - VKILL, - VLNEXT, - #[cfg(not(any(all(target_os = "linux", target_arch = "sparc64"), - target_os = "illumos", target_os = "solaris")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - VMIN, - VQUIT, - VREPRINT, - VSTART, - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - VSTATUS, - VSTOP, - VSUSP, - #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - VSWTC, - #[cfg(any(target_os = "haiku", target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - VSWTCH, - #[cfg(not(any(all(target_os = "linux", target_arch = "sparc64"), - target_os = "illumos", target_os = "solaris")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - VTIME, - VWERASE, - #[cfg(target_os = "dragonfly")] - #[cfg_attr(docsrs, doc(cfg(all())))] - VCHECKPT, - } -} - -#[cfg(any( - all(target_os = "linux", target_arch = "sparc64"), - target_os = "illumos", - target_os = "solaris" -))] -impl SpecialCharacterIndices { - pub const VMIN: SpecialCharacterIndices = SpecialCharacterIndices::VEOF; - pub const VTIME: SpecialCharacterIndices = SpecialCharacterIndices::VEOL; -} - -pub use libc::NCCS; -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" -))] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub use libc::_POSIX_VDISABLE; - -libc_bitflags! { - /// Flags for configuring the input mode of a terminal - pub struct InputFlags: tcflag_t { - IGNBRK; - BRKINT; - IGNPAR; - PARMRK; - INPCK; - ISTRIP; - INLCR; - IGNCR; - ICRNL; - IXON; - IXOFF; - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IXANY; - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IMAXBEL; - #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IUTF8; - } -} - -libc_bitflags! { - /// Flags for configuring the output mode of a terminal - pub struct OutputFlags: tcflag_t { - OPOST; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "linux", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - OLCUC; - ONLCR; - OCRNL as tcflag_t; - ONOCR as tcflag_t; - ONLRET as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - OFILL as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - OFDEL as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NL0 as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NL1 as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - CR0 as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - CR1 as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - CR2 as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - CR3 as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "freebsd", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - TAB0 as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - TAB1 as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - TAB2 as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "freebsd", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - TAB3 as tcflag_t; - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - XTABS; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - BS0 as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - BS1 as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - VT0 as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - VT1 as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - FF0 as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - FF1 as tcflag_t; - #[cfg(any(target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - OXTABS; - #[cfg(any(target_os = "freebsd", - target_os = "dragonfly", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ONOEOT as tcflag_t; - - // Bitmasks for use with OutputFlags to select specific settings - // These should be moved to be a mask once https://github.com/rust-lang-nursery/bitflags/issues/110 - // is resolved. - - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NLDLY as tcflag_t; // FIXME: Datatype needs to be corrected in libc for mac - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - CRDLY as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "freebsd", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - TABDLY as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - BSDLY as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - VTDLY as tcflag_t; - #[cfg(any(target_os = "android", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - FFDLY as tcflag_t; - } -} - -libc_bitflags! { - /// Flags for setting the control mode of a terminal - pub struct ControlFlags: tcflag_t { - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - CIGNORE; - CS5; - CS6; - CS7; - CS8; - CSTOPB; - CREAD; - PARENB; - PARODD; - HUPCL; - CLOCAL; - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - CRTSCTS; - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - CBAUD; - #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "mips"))))] - #[cfg_attr(docsrs, doc(cfg(all())))] - CMSPAR; - #[cfg(any(target_os = "android", - all(target_os = "linux", - not(any(target_arch = "powerpc", target_arch = "powerpc64")))))] - CIBAUD; - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - CBAUDEX; - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MDMBUF; - #[cfg(any(target_os = "netbsd", target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - CHWFLOW; - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - CCTS_OFLOW; - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - CRTS_IFLOW; - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - CDTR_IFLOW; - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - CDSR_OFLOW; - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - CCAR_OFLOW; - - // Bitmasks for use with ControlFlags to select specific settings - // These should be moved to be a mask once https://github.com/rust-lang-nursery/bitflags/issues/110 - // is resolved. - - CSIZE; - } -} - -libc_bitflags! { - /// Flags for setting any local modes - pub struct LocalFlags: tcflag_t { - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ECHOKE; - ECHOE; - ECHOK; - ECHO; - ECHONL; - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ECHOPRT; - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ECHOCTL; - ISIG; - ICANON; - #[cfg(any(target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ALTWERASE; - IEXTEN; - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - EXTPROC; - TOSTOP; - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - FLUSHO; - #[cfg(any(target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - NOKERNINFO; - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - PENDIN; - NOFLSH; - } -} - -cfg_if! { - if #[cfg(any(target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] { - /// Get input baud rate (see - /// [cfgetispeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html)). - /// - /// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure. - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - pub fn cfgetispeed(termios: &Termios) -> u32 { - let inner_termios = termios.get_libc_termios(); - unsafe { libc::cfgetispeed(&*inner_termios) as u32 } - } - - /// Get output baud rate (see - /// [cfgetospeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetospeed.html)). - /// - /// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure. - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - pub fn cfgetospeed(termios: &Termios) -> u32 { - let inner_termios = termios.get_libc_termios(); - unsafe { libc::cfgetospeed(&*inner_termios) as u32 } - } - - /// Set input baud rate (see - /// [cfsetispeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetispeed.html)). - /// - /// `cfsetispeed()` sets the intput baud rate in the given `Termios` structure. - pub fn cfsetispeed<T: Into<u32>>(termios: &mut Termios, baud: T) -> Result<()> { - let inner_termios = unsafe { termios.get_libc_termios_mut() }; - let res = unsafe { libc::cfsetispeed(inner_termios, baud.into() as libc::speed_t) }; - termios.update_wrapper(); - Errno::result(res).map(drop) - } - - /// Set output baud rate (see - /// [cfsetospeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetospeed.html)). - /// - /// `cfsetospeed()` sets the output baud rate in the given termios structure. - pub fn cfsetospeed<T: Into<u32>>(termios: &mut Termios, baud: T) -> Result<()> { - let inner_termios = unsafe { termios.get_libc_termios_mut() }; - let res = unsafe { libc::cfsetospeed(inner_termios, baud.into() as libc::speed_t) }; - termios.update_wrapper(); - Errno::result(res).map(drop) - } - - /// Set both the input and output baud rates (see - /// [termios(3)](https://www.freebsd.org/cgi/man.cgi?query=cfsetspeed)). - /// - /// `cfsetspeed()` sets the input and output baud rate in the given termios structure. Note that - /// this is part of the 4.4BSD standard and not part of POSIX. - pub fn cfsetspeed<T: Into<u32>>(termios: &mut Termios, baud: T) -> Result<()> { - let inner_termios = unsafe { termios.get_libc_termios_mut() }; - let res = unsafe { libc::cfsetspeed(inner_termios, baud.into() as libc::speed_t) }; - termios.update_wrapper(); - Errno::result(res).map(drop) - } - } else { - use std::convert::TryInto; - - /// Get input baud rate (see - /// [cfgetispeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html)). - /// - /// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure. - pub fn cfgetispeed(termios: &Termios) -> BaudRate { - let inner_termios = termios.get_libc_termios(); - unsafe { libc::cfgetispeed(&*inner_termios) }.try_into().unwrap() - } - - /// Get output baud rate (see - /// [cfgetospeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetospeed.html)). - /// - /// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure. - pub fn cfgetospeed(termios: &Termios) -> BaudRate { - let inner_termios = termios.get_libc_termios(); - unsafe { libc::cfgetospeed(&*inner_termios) }.try_into().unwrap() - } - - /// Set input baud rate (see - /// [cfsetispeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetispeed.html)). - /// - /// `cfsetispeed()` sets the intput baud rate in the given `Termios` structure. - pub fn cfsetispeed(termios: &mut Termios, baud: BaudRate) -> Result<()> { - let inner_termios = unsafe { termios.get_libc_termios_mut() }; - let res = unsafe { libc::cfsetispeed(inner_termios, baud as libc::speed_t) }; - termios.update_wrapper(); - Errno::result(res).map(drop) - } - - /// Set output baud rate (see - /// [cfsetospeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetospeed.html)). - /// - /// `cfsetospeed()` sets the output baud rate in the given `Termios` structure. - pub fn cfsetospeed(termios: &mut Termios, baud: BaudRate) -> Result<()> { - let inner_termios = unsafe { termios.get_libc_termios_mut() }; - let res = unsafe { libc::cfsetospeed(inner_termios, baud as libc::speed_t) }; - termios.update_wrapper(); - Errno::result(res).map(drop) - } - - /// Set both the input and output baud rates (see - /// [termios(3)](https://www.freebsd.org/cgi/man.cgi?query=cfsetspeed)). - /// - /// `cfsetspeed()` sets the input and output baud rate in the given `Termios` structure. Note that - /// this is part of the 4.4BSD standard and not part of POSIX. - #[cfg(not(target_os = "haiku"))] - pub fn cfsetspeed(termios: &mut Termios, baud: BaudRate) -> Result<()> { - let inner_termios = unsafe { termios.get_libc_termios_mut() }; - let res = unsafe { libc::cfsetspeed(inner_termios, baud as libc::speed_t) }; - termios.update_wrapper(); - Errno::result(res).map(drop) - } - } -} - -/// Configures the port to something like the "raw" mode of the old Version 7 terminal driver (see -/// [termios(3)](https://man7.org/linux/man-pages/man3/termios.3.html)). -/// -/// `cfmakeraw()` configures the termios structure such that input is available character-by- -/// character, echoing is disabled, and all special input and output processing is disabled. Note -/// that this is a non-standard function, but is available on Linux and BSDs. -pub fn cfmakeraw(termios: &mut Termios) { - let inner_termios = unsafe { termios.get_libc_termios_mut() }; - unsafe { - libc::cfmakeraw(inner_termios); - } - termios.update_wrapper(); -} - -/// Configures the port to "sane" mode (like the configuration of a newly created terminal) (see -/// [tcsetattr(3)](https://www.freebsd.org/cgi/man.cgi?query=tcsetattr)). -/// -/// Note that this is a non-standard function, available on FreeBSD. -#[cfg(target_os = "freebsd")] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub fn cfmakesane(termios: &mut Termios) { - let inner_termios = unsafe { termios.get_libc_termios_mut() }; - unsafe { - libc::cfmakesane(inner_termios); - } - termios.update_wrapper(); -} - -/// Return the configuration of a port -/// [tcgetattr(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetattr.html)). -/// -/// `tcgetattr()` returns a `Termios` structure with the current configuration for a port. Modifying -/// this structure *will not* reconfigure the port, instead the modifications should be done to -/// the `Termios` structure and then the port should be reconfigured using `tcsetattr()`. -pub fn tcgetattr(fd: RawFd) -> Result<Termios> { - let mut termios = mem::MaybeUninit::uninit(); - - let res = unsafe { libc::tcgetattr(fd, termios.as_mut_ptr()) }; - - Errno::result(res)?; - - unsafe { Ok(termios.assume_init().into()) } -} - -/// Set the configuration for a terminal (see -/// [tcsetattr(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetattr.html)). -/// -/// `tcsetattr()` reconfigures the given port based on a given `Termios` structure. This change -/// takes affect at a time specified by `actions`. Note that this function may return success if -/// *any* of the parameters were successfully set, not only if all were set successfully. -pub fn tcsetattr(fd: RawFd, actions: SetArg, termios: &Termios) -> Result<()> { - let inner_termios = termios.get_libc_termios(); - Errno::result(unsafe { - libc::tcsetattr(fd, actions as c_int, &*inner_termios) - }) - .map(drop) -} - -/// Block until all output data is written (see -/// [tcdrain(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcdrain.html)). -pub fn tcdrain(fd: RawFd) -> Result<()> { - Errno::result(unsafe { libc::tcdrain(fd) }).map(drop) -} - -/// Suspend or resume the transmission or reception of data (see -/// [tcflow(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcflow.html)). -/// -/// `tcflow()` suspends of resumes the transmission or reception of data for the given port -/// depending on the value of `action`. -pub fn tcflow(fd: RawFd, action: FlowArg) -> Result<()> { - Errno::result(unsafe { libc::tcflow(fd, action as c_int) }).map(drop) -} - -/// Discard data in the output or input queue (see -/// [tcflush(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcflush.html)). -/// -/// `tcflush()` will discard data for a terminal port in the input queue, output queue, or both -/// depending on the value of `action`. -pub fn tcflush(fd: RawFd, action: FlushArg) -> Result<()> { - Errno::result(unsafe { libc::tcflush(fd, action as c_int) }).map(drop) -} - -/// Send a break for a specific duration (see -/// [tcsendbreak(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsendbreak.html)). -/// -/// When using asynchronous data transmission `tcsendbreak()` will transmit a continuous stream -/// of zero-valued bits for an implementation-defined duration. -pub fn tcsendbreak(fd: RawFd, duration: c_int) -> Result<()> { - Errno::result(unsafe { libc::tcsendbreak(fd, duration) }).map(drop) -} - -feature! { -#![feature = "process"] -/// Get the session controlled by the given terminal (see -/// [tcgetsid(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetsid.html)). -pub fn tcgetsid(fd: RawFd) -> Result<Pid> { - let res = unsafe { libc::tcgetsid(fd) }; - - Errno::result(res).map(Pid::from_raw) -} -} - -#[cfg(test)] -mod test { - use super::*; - use std::convert::TryFrom; - - #[test] - fn try_from() { - assert_eq!(Ok(BaudRate::B0), BaudRate::try_from(libc::B0)); - #[cfg(not(target_os = "haiku"))] - BaudRate::try_from(999999999).expect_err("assertion failed"); - #[cfg(target_os = "haiku")] - BaudRate::try_from(99).expect_err("assertion failed"); - } -} diff --git a/vendor/nix/src/sys/time.rs b/vendor/nix/src/sys/time.rs deleted file mode 100644 index 0042c4508..000000000 --- a/vendor/nix/src/sys/time.rs +++ /dev/null @@ -1,811 +0,0 @@ -#[cfg_attr(target_env = "musl", allow(deprecated))] -// https://github.com/rust-lang/libc/issues/1848 -pub use libc::{suseconds_t, time_t}; -use libc::{timespec, timeval}; -use std::convert::From; -use std::time::Duration; -use std::{cmp, fmt, ops}; - -const fn zero_init_timespec() -> timespec { - // `std::mem::MaybeUninit::zeroed()` is not yet a const fn - // (https://github.com/rust-lang/rust/issues/91850) so we will instead initialize an array of - // the appropriate size to zero and then transmute it to a timespec value. - unsafe { std::mem::transmute([0u8; std::mem::size_of::<timespec>()]) } -} - -#[cfg(any( - all(feature = "time", any(target_os = "android", target_os = "linux")), - all( - any( - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd" - ), - feature = "time", - feature = "signal" - ) -))] -pub(crate) mod timer { - use crate::sys::time::{zero_init_timespec, TimeSpec}; - use bitflags::bitflags; - - #[derive(Debug, Clone, Copy)] - pub(crate) struct TimerSpec(libc::itimerspec); - - impl TimerSpec { - pub const fn none() -> Self { - Self(libc::itimerspec { - it_interval: zero_init_timespec(), - it_value: zero_init_timespec(), - }) - } - } - - impl AsMut<libc::itimerspec> for TimerSpec { - fn as_mut(&mut self) -> &mut libc::itimerspec { - &mut self.0 - } - } - - impl AsRef<libc::itimerspec> for TimerSpec { - fn as_ref(&self) -> &libc::itimerspec { - &self.0 - } - } - - impl From<Expiration> for TimerSpec { - fn from(expiration: Expiration) -> TimerSpec { - match expiration { - Expiration::OneShot(t) => TimerSpec(libc::itimerspec { - it_interval: zero_init_timespec(), - it_value: *t.as_ref(), - }), - Expiration::IntervalDelayed(start, interval) => { - TimerSpec(libc::itimerspec { - it_interval: *interval.as_ref(), - it_value: *start.as_ref(), - }) - } - Expiration::Interval(t) => TimerSpec(libc::itimerspec { - it_interval: *t.as_ref(), - it_value: *t.as_ref(), - }), - } - } - } - - /// An enumeration allowing the definition of the expiration time of an alarm, - /// recurring or not. - #[derive(Debug, Clone, Copy, Eq, PartialEq)] - pub enum Expiration { - /// Alarm will trigger once after the time given in `TimeSpec` - OneShot(TimeSpec), - /// Alarm will trigger after a specified delay and then every interval of - /// time. - IntervalDelayed(TimeSpec, TimeSpec), - /// Alarm will trigger every specified interval of time. - Interval(TimeSpec), - } - - #[cfg(any(target_os = "android", target_os = "linux"))] - bitflags! { - /// Flags that are used for arming the timer. - pub struct TimerSetTimeFlags: libc::c_int { - const TFD_TIMER_ABSTIME = libc::TFD_TIMER_ABSTIME; - } - } - #[cfg(any( - target_os = "freebsd", - target_os = "netbsd", - target_os = "dragonfly", - target_os = "illumos" - ))] - bitflags! { - /// Flags that are used for arming the timer. - pub struct TimerSetTimeFlags: libc::c_int { - const TFD_TIMER_ABSTIME = libc::TIMER_ABSTIME; - } - } - - impl From<TimerSpec> for Expiration { - fn from(timerspec: TimerSpec) -> Expiration { - match timerspec { - TimerSpec(libc::itimerspec { - it_interval: - libc::timespec { - tv_sec: 0, - tv_nsec: 0, - .. - }, - it_value: ts, - }) => Expiration::OneShot(ts.into()), - TimerSpec(libc::itimerspec { - it_interval: int_ts, - it_value: val_ts, - }) => { - if (int_ts.tv_sec == val_ts.tv_sec) - && (int_ts.tv_nsec == val_ts.tv_nsec) - { - Expiration::Interval(int_ts.into()) - } else { - Expiration::IntervalDelayed( - val_ts.into(), - int_ts.into(), - ) - } - } - } - } - } -} - -pub trait TimeValLike: Sized { - #[inline] - fn zero() -> Self { - Self::seconds(0) - } - - #[inline] - fn hours(hours: i64) -> Self { - let secs = hours - .checked_mul(SECS_PER_HOUR) - .expect("TimeValLike::hours ouf of bounds"); - Self::seconds(secs) - } - - #[inline] - fn minutes(minutes: i64) -> Self { - let secs = minutes - .checked_mul(SECS_PER_MINUTE) - .expect("TimeValLike::minutes out of bounds"); - Self::seconds(secs) - } - - fn seconds(seconds: i64) -> Self; - fn milliseconds(milliseconds: i64) -> Self; - fn microseconds(microseconds: i64) -> Self; - fn nanoseconds(nanoseconds: i64) -> Self; - - #[inline] - fn num_hours(&self) -> i64 { - self.num_seconds() / 3600 - } - - #[inline] - fn num_minutes(&self) -> i64 { - self.num_seconds() / 60 - } - - fn num_seconds(&self) -> i64; - fn num_milliseconds(&self) -> i64; - fn num_microseconds(&self) -> i64; - fn num_nanoseconds(&self) -> i64; -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct TimeSpec(timespec); - -const NANOS_PER_SEC: i64 = 1_000_000_000; -const SECS_PER_MINUTE: i64 = 60; -const SECS_PER_HOUR: i64 = 3600; - -#[cfg(target_pointer_width = "64")] -const TS_MAX_SECONDS: i64 = (i64::MAX / NANOS_PER_SEC) - 1; - -#[cfg(target_pointer_width = "32")] -const TS_MAX_SECONDS: i64 = isize::MAX as i64; - -const TS_MIN_SECONDS: i64 = -TS_MAX_SECONDS; - -// x32 compatibility -// See https://sourceware.org/bugzilla/show_bug.cgi?id=16437 -#[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] -type timespec_tv_nsec_t = i64; -#[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] -type timespec_tv_nsec_t = libc::c_long; - -impl From<timespec> for TimeSpec { - fn from(ts: timespec) -> Self { - Self(ts) - } -} - -impl From<Duration> for TimeSpec { - fn from(duration: Duration) -> Self { - Self::from_duration(duration) - } -} - -impl From<TimeSpec> for Duration { - fn from(timespec: TimeSpec) -> Self { - Duration::new(timespec.0.tv_sec as u64, timespec.0.tv_nsec as u32) - } -} - -impl AsRef<timespec> for TimeSpec { - fn as_ref(&self) -> ×pec { - &self.0 - } -} - -impl AsMut<timespec> for TimeSpec { - fn as_mut(&mut self) -> &mut timespec { - &mut self.0 - } -} - -impl Ord for TimeSpec { - // The implementation of cmp is simplified by assuming that the struct is - // normalized. That is, tv_nsec must always be within [0, 1_000_000_000) - fn cmp(&self, other: &TimeSpec) -> cmp::Ordering { - if self.tv_sec() == other.tv_sec() { - self.tv_nsec().cmp(&other.tv_nsec()) - } else { - self.tv_sec().cmp(&other.tv_sec()) - } - } -} - -impl PartialOrd for TimeSpec { - fn partial_cmp(&self, other: &TimeSpec) -> Option<cmp::Ordering> { - Some(self.cmp(other)) - } -} - -impl TimeValLike for TimeSpec { - #[inline] - #[cfg_attr(target_env = "musl", allow(deprecated))] - // https://github.com/rust-lang/libc/issues/1848 - fn seconds(seconds: i64) -> TimeSpec { - assert!( - (TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&seconds), - "TimeSpec out of bounds; seconds={}", - seconds - ); - let mut ts = zero_init_timespec(); - ts.tv_sec = seconds as time_t; - TimeSpec(ts) - } - - #[inline] - fn milliseconds(milliseconds: i64) -> TimeSpec { - let nanoseconds = milliseconds - .checked_mul(1_000_000) - .expect("TimeSpec::milliseconds out of bounds"); - - TimeSpec::nanoseconds(nanoseconds) - } - - /// Makes a new `TimeSpec` with given number of microseconds. - #[inline] - fn microseconds(microseconds: i64) -> TimeSpec { - let nanoseconds = microseconds - .checked_mul(1_000) - .expect("TimeSpec::milliseconds out of bounds"); - - TimeSpec::nanoseconds(nanoseconds) - } - - /// Makes a new `TimeSpec` with given number of nanoseconds. - #[inline] - #[cfg_attr(target_env = "musl", allow(deprecated))] - // https://github.com/rust-lang/libc/issues/1848 - fn nanoseconds(nanoseconds: i64) -> TimeSpec { - let (secs, nanos) = div_mod_floor_64(nanoseconds, NANOS_PER_SEC); - assert!( - (TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&secs), - "TimeSpec out of bounds" - ); - let mut ts = zero_init_timespec(); - ts.tv_sec = secs as time_t; - ts.tv_nsec = nanos as timespec_tv_nsec_t; - TimeSpec(ts) - } - - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - fn num_seconds(&self) -> i64 { - if self.tv_sec() < 0 && self.tv_nsec() > 0 { - (self.tv_sec() + 1) as i64 - } else { - self.tv_sec() as i64 - } - } - - fn num_milliseconds(&self) -> i64 { - self.num_nanoseconds() / 1_000_000 - } - - fn num_microseconds(&self) -> i64 { - self.num_nanoseconds() / 1_000 - } - - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - fn num_nanoseconds(&self) -> i64 { - let secs = self.num_seconds() * 1_000_000_000; - let nsec = self.nanos_mod_sec(); - secs + nsec as i64 - } -} - -impl TimeSpec { - /// Construct a new `TimeSpec` from its components - #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 - pub const fn new(seconds: time_t, nanoseconds: timespec_tv_nsec_t) -> Self { - let mut ts = zero_init_timespec(); - ts.tv_sec = seconds; - ts.tv_nsec = nanoseconds; - Self(ts) - } - - fn nanos_mod_sec(&self) -> timespec_tv_nsec_t { - if self.tv_sec() < 0 && self.tv_nsec() > 0 { - self.tv_nsec() - NANOS_PER_SEC as timespec_tv_nsec_t - } else { - self.tv_nsec() - } - } - - #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 - pub const fn tv_sec(&self) -> time_t { - self.0.tv_sec - } - - pub const fn tv_nsec(&self) -> timespec_tv_nsec_t { - self.0.tv_nsec - } - - #[cfg_attr(target_env = "musl", allow(deprecated))] - // https://github.com/rust-lang/libc/issues/1848 - pub const fn from_duration(duration: Duration) -> Self { - let mut ts = zero_init_timespec(); - ts.tv_sec = duration.as_secs() as time_t; - ts.tv_nsec = duration.subsec_nanos() as timespec_tv_nsec_t; - TimeSpec(ts) - } - - pub const fn from_timespec(timespec: timespec) -> Self { - Self(timespec) - } -} - -impl ops::Neg for TimeSpec { - type Output = TimeSpec; - - fn neg(self) -> TimeSpec { - TimeSpec::nanoseconds(-self.num_nanoseconds()) - } -} - -impl ops::Add for TimeSpec { - type Output = TimeSpec; - - fn add(self, rhs: TimeSpec) -> TimeSpec { - TimeSpec::nanoseconds(self.num_nanoseconds() + rhs.num_nanoseconds()) - } -} - -impl ops::Sub for TimeSpec { - type Output = TimeSpec; - - fn sub(self, rhs: TimeSpec) -> TimeSpec { - TimeSpec::nanoseconds(self.num_nanoseconds() - rhs.num_nanoseconds()) - } -} - -impl ops::Mul<i32> for TimeSpec { - type Output = TimeSpec; - - fn mul(self, rhs: i32) -> TimeSpec { - let usec = self - .num_nanoseconds() - .checked_mul(i64::from(rhs)) - .expect("TimeSpec multiply out of bounds"); - - TimeSpec::nanoseconds(usec) - } -} - -impl ops::Div<i32> for TimeSpec { - type Output = TimeSpec; - - fn div(self, rhs: i32) -> TimeSpec { - let usec = self.num_nanoseconds() / i64::from(rhs); - TimeSpec::nanoseconds(usec) - } -} - -impl fmt::Display for TimeSpec { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let (abs, sign) = if self.tv_sec() < 0 { - (-*self, "-") - } else { - (*self, "") - }; - - let sec = abs.tv_sec(); - - write!(f, "{}", sign)?; - - if abs.tv_nsec() == 0 { - if abs.tv_sec() == 1 { - write!(f, "{} second", sec)?; - } else { - write!(f, "{} seconds", sec)?; - } - } else if abs.tv_nsec() % 1_000_000 == 0 { - write!(f, "{}.{:03} seconds", sec, abs.tv_nsec() / 1_000_000)?; - } else if abs.tv_nsec() % 1_000 == 0 { - write!(f, "{}.{:06} seconds", sec, abs.tv_nsec() / 1_000)?; - } else { - write!(f, "{}.{:09} seconds", sec, abs.tv_nsec())?; - } - - Ok(()) - } -} - -#[repr(transparent)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct TimeVal(timeval); - -const MICROS_PER_SEC: i64 = 1_000_000; - -#[cfg(target_pointer_width = "64")] -const TV_MAX_SECONDS: i64 = (i64::MAX / MICROS_PER_SEC) - 1; - -#[cfg(target_pointer_width = "32")] -const TV_MAX_SECONDS: i64 = isize::MAX as i64; - -const TV_MIN_SECONDS: i64 = -TV_MAX_SECONDS; - -impl AsRef<timeval> for TimeVal { - fn as_ref(&self) -> &timeval { - &self.0 - } -} - -impl AsMut<timeval> for TimeVal { - fn as_mut(&mut self) -> &mut timeval { - &mut self.0 - } -} - -impl Ord for TimeVal { - // The implementation of cmp is simplified by assuming that the struct is - // normalized. That is, tv_usec must always be within [0, 1_000_000) - fn cmp(&self, other: &TimeVal) -> cmp::Ordering { - if self.tv_sec() == other.tv_sec() { - self.tv_usec().cmp(&other.tv_usec()) - } else { - self.tv_sec().cmp(&other.tv_sec()) - } - } -} - -impl PartialOrd for TimeVal { - fn partial_cmp(&self, other: &TimeVal) -> Option<cmp::Ordering> { - Some(self.cmp(other)) - } -} - -impl TimeValLike for TimeVal { - #[inline] - fn seconds(seconds: i64) -> TimeVal { - assert!( - (TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&seconds), - "TimeVal out of bounds; seconds={}", - seconds - ); - #[cfg_attr(target_env = "musl", allow(deprecated))] - // https://github.com/rust-lang/libc/issues/1848 - TimeVal(timeval { - tv_sec: seconds as time_t, - tv_usec: 0, - }) - } - - #[inline] - fn milliseconds(milliseconds: i64) -> TimeVal { - let microseconds = milliseconds - .checked_mul(1_000) - .expect("TimeVal::milliseconds out of bounds"); - - TimeVal::microseconds(microseconds) - } - - /// Makes a new `TimeVal` with given number of microseconds. - #[inline] - fn microseconds(microseconds: i64) -> TimeVal { - let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC); - assert!( - (TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&secs), - "TimeVal out of bounds" - ); - #[cfg_attr(target_env = "musl", allow(deprecated))] - // https://github.com/rust-lang/libc/issues/1848 - TimeVal(timeval { - tv_sec: secs as time_t, - tv_usec: micros as suseconds_t, - }) - } - - /// Makes a new `TimeVal` with given number of nanoseconds. Some precision - /// will be lost - #[inline] - fn nanoseconds(nanoseconds: i64) -> TimeVal { - let microseconds = nanoseconds / 1000; - let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC); - assert!( - (TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&secs), - "TimeVal out of bounds" - ); - #[cfg_attr(target_env = "musl", allow(deprecated))] - // https://github.com/rust-lang/libc/issues/1848 - TimeVal(timeval { - tv_sec: secs as time_t, - tv_usec: micros as suseconds_t, - }) - } - - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - fn num_seconds(&self) -> i64 { - if self.tv_sec() < 0 && self.tv_usec() > 0 { - (self.tv_sec() + 1) as i64 - } else { - self.tv_sec() as i64 - } - } - - fn num_milliseconds(&self) -> i64 { - self.num_microseconds() / 1_000 - } - - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - fn num_microseconds(&self) -> i64 { - let secs = self.num_seconds() * 1_000_000; - let usec = self.micros_mod_sec(); - secs + usec as i64 - } - - fn num_nanoseconds(&self) -> i64 { - self.num_microseconds() * 1_000 - } -} - -impl TimeVal { - /// Construct a new `TimeVal` from its components - #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 - pub const fn new(seconds: time_t, microseconds: suseconds_t) -> Self { - Self(timeval { - tv_sec: seconds, - tv_usec: microseconds, - }) - } - - fn micros_mod_sec(&self) -> suseconds_t { - if self.tv_sec() < 0 && self.tv_usec() > 0 { - self.tv_usec() - MICROS_PER_SEC as suseconds_t - } else { - self.tv_usec() - } - } - - #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 - pub const fn tv_sec(&self) -> time_t { - self.0.tv_sec - } - - pub const fn tv_usec(&self) -> suseconds_t { - self.0.tv_usec - } -} - -impl ops::Neg for TimeVal { - type Output = TimeVal; - - fn neg(self) -> TimeVal { - TimeVal::microseconds(-self.num_microseconds()) - } -} - -impl ops::Add for TimeVal { - type Output = TimeVal; - - fn add(self, rhs: TimeVal) -> TimeVal { - TimeVal::microseconds(self.num_microseconds() + rhs.num_microseconds()) - } -} - -impl ops::Sub for TimeVal { - type Output = TimeVal; - - fn sub(self, rhs: TimeVal) -> TimeVal { - TimeVal::microseconds(self.num_microseconds() - rhs.num_microseconds()) - } -} - -impl ops::Mul<i32> for TimeVal { - type Output = TimeVal; - - fn mul(self, rhs: i32) -> TimeVal { - let usec = self - .num_microseconds() - .checked_mul(i64::from(rhs)) - .expect("TimeVal multiply out of bounds"); - - TimeVal::microseconds(usec) - } -} - -impl ops::Div<i32> for TimeVal { - type Output = TimeVal; - - fn div(self, rhs: i32) -> TimeVal { - let usec = self.num_microseconds() / i64::from(rhs); - TimeVal::microseconds(usec) - } -} - -impl fmt::Display for TimeVal { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let (abs, sign) = if self.tv_sec() < 0 { - (-*self, "-") - } else { - (*self, "") - }; - - let sec = abs.tv_sec(); - - write!(f, "{}", sign)?; - - if abs.tv_usec() == 0 { - if abs.tv_sec() == 1 { - write!(f, "{} second", sec)?; - } else { - write!(f, "{} seconds", sec)?; - } - } else if abs.tv_usec() % 1000 == 0 { - write!(f, "{}.{:03} seconds", sec, abs.tv_usec() / 1000)?; - } else { - write!(f, "{}.{:06} seconds", sec, abs.tv_usec())?; - } - - Ok(()) - } -} - -impl From<timeval> for TimeVal { - fn from(tv: timeval) -> Self { - TimeVal(tv) - } -} - -#[inline] -fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) { - (div_floor_64(this, other), mod_floor_64(this, other)) -} - -#[inline] -fn div_floor_64(this: i64, other: i64) -> i64 { - match div_rem_64(this, other) { - (d, r) if (r > 0 && other < 0) || (r < 0 && other > 0) => d - 1, - (d, _) => d, - } -} - -#[inline] -fn mod_floor_64(this: i64, other: i64) -> i64 { - match this % other { - r if (r > 0 && other < 0) || (r < 0 && other > 0) => r + other, - r => r, - } -} - -#[inline] -fn div_rem_64(this: i64, other: i64) -> (i64, i64) { - (this / other, this % other) -} - -#[cfg(test)] -mod test { - use super::{TimeSpec, TimeVal, TimeValLike}; - use std::time::Duration; - - #[test] - pub fn test_timespec() { - assert_ne!(TimeSpec::seconds(1), TimeSpec::zero()); - assert_eq!( - TimeSpec::seconds(1) + TimeSpec::seconds(2), - TimeSpec::seconds(3) - ); - assert_eq!( - TimeSpec::minutes(3) + TimeSpec::seconds(2), - TimeSpec::seconds(182) - ); - } - - #[test] - pub fn test_timespec_from() { - let duration = Duration::new(123, 123_456_789); - let timespec = TimeSpec::nanoseconds(123_123_456_789); - - assert_eq!(TimeSpec::from(duration), timespec); - assert_eq!(Duration::from(timespec), duration); - } - - #[test] - pub fn test_timespec_neg() { - let a = TimeSpec::seconds(1) + TimeSpec::nanoseconds(123); - let b = TimeSpec::seconds(-1) + TimeSpec::nanoseconds(-123); - - assert_eq!(a, -b); - } - - #[test] - pub fn test_timespec_ord() { - assert_eq!(TimeSpec::seconds(1), TimeSpec::nanoseconds(1_000_000_000)); - assert!(TimeSpec::seconds(1) < TimeSpec::nanoseconds(1_000_000_001)); - assert!(TimeSpec::seconds(1) > TimeSpec::nanoseconds(999_999_999)); - assert!(TimeSpec::seconds(-1) < TimeSpec::nanoseconds(-999_999_999)); - assert!(TimeSpec::seconds(-1) > TimeSpec::nanoseconds(-1_000_000_001)); - } - - #[test] - pub fn test_timespec_fmt() { - assert_eq!(TimeSpec::zero().to_string(), "0 seconds"); - assert_eq!(TimeSpec::seconds(42).to_string(), "42 seconds"); - assert_eq!(TimeSpec::milliseconds(42).to_string(), "0.042 seconds"); - assert_eq!(TimeSpec::microseconds(42).to_string(), "0.000042 seconds"); - assert_eq!( - TimeSpec::nanoseconds(42).to_string(), - "0.000000042 seconds" - ); - assert_eq!(TimeSpec::seconds(-86401).to_string(), "-86401 seconds"); - } - - #[test] - pub fn test_timeval() { - assert_ne!(TimeVal::seconds(1), TimeVal::zero()); - assert_eq!( - TimeVal::seconds(1) + TimeVal::seconds(2), - TimeVal::seconds(3) - ); - assert_eq!( - TimeVal::minutes(3) + TimeVal::seconds(2), - TimeVal::seconds(182) - ); - } - - #[test] - pub fn test_timeval_ord() { - assert_eq!(TimeVal::seconds(1), TimeVal::microseconds(1_000_000)); - assert!(TimeVal::seconds(1) < TimeVal::microseconds(1_000_001)); - assert!(TimeVal::seconds(1) > TimeVal::microseconds(999_999)); - assert!(TimeVal::seconds(-1) < TimeVal::microseconds(-999_999)); - assert!(TimeVal::seconds(-1) > TimeVal::microseconds(-1_000_001)); - } - - #[test] - pub fn test_timeval_neg() { - let a = TimeVal::seconds(1) + TimeVal::microseconds(123); - let b = TimeVal::seconds(-1) + TimeVal::microseconds(-123); - - assert_eq!(a, -b); - } - - #[test] - pub fn test_timeval_fmt() { - assert_eq!(TimeVal::zero().to_string(), "0 seconds"); - assert_eq!(TimeVal::seconds(42).to_string(), "42 seconds"); - assert_eq!(TimeVal::milliseconds(42).to_string(), "0.042 seconds"); - assert_eq!(TimeVal::microseconds(42).to_string(), "0.000042 seconds"); - assert_eq!(TimeVal::nanoseconds(1402).to_string(), "0.000001 seconds"); - assert_eq!(TimeVal::seconds(-86401).to_string(), "-86401 seconds"); - } -} diff --git a/vendor/nix/src/sys/timer.rs b/vendor/nix/src/sys/timer.rs deleted file mode 100644 index e1a34051e..000000000 --- a/vendor/nix/src/sys/timer.rs +++ /dev/null @@ -1,187 +0,0 @@ -//! Timer API via signals. -//! -//! Timer is a POSIX API to create timers and get expiration notifications -//! through queued Unix signals, for the current process. This is similar to -//! Linux's timerfd mechanism, except that API is specific to Linux and makes -//! use of file polling. -//! -//! For more documentation, please read [timer_create](https://pubs.opengroup.org/onlinepubs/9699919799/functions/timer_create.html). -//! -//! # Examples -//! -//! Create an interval timer that signals SIGALARM every 250 milliseconds. -//! -//! ```no_run -//! use nix::sys::signal::{self, SigEvent, SigHandler, SigevNotify, Signal}; -//! use nix::sys::timer::{Expiration, Timer, TimerSetTimeFlags}; -//! use nix::time::ClockId; -//! use std::convert::TryFrom; -//! use std::sync::atomic::{AtomicU64, Ordering}; -//! use std::thread::yield_now; -//! use std::time::Duration; -//! -//! const SIG: Signal = Signal::SIGALRM; -//! static ALARMS: AtomicU64 = AtomicU64::new(0); -//! -//! extern "C" fn handle_alarm(signal: libc::c_int) { -//! let signal = Signal::try_from(signal).unwrap(); -//! if signal == SIG { -//! ALARMS.fetch_add(1, Ordering::Relaxed); -//! } -//! } -//! -//! fn main() { -//! let clockid = ClockId::CLOCK_MONOTONIC; -//! let sigevent = SigEvent::new(SigevNotify::SigevSignal { -//! signal: SIG, -//! si_value: 0, -//! }); -//! -//! let mut timer = Timer::new(clockid, sigevent).unwrap(); -//! let expiration = Expiration::Interval(Duration::from_millis(250).into()); -//! let flags = TimerSetTimeFlags::empty(); -//! timer.set(expiration, flags).expect("could not set timer"); -//! -//! let handler = SigHandler::Handler(handle_alarm); -//! unsafe { signal::signal(SIG, handler) }.unwrap(); -//! -//! loop { -//! let alarms = ALARMS.load(Ordering::Relaxed); -//! if alarms >= 10 { -//! println!("total alarms handled: {}", alarms); -//! break; -//! } -//! yield_now() -//! } -//! } -//! ``` -use crate::sys::signal::SigEvent; -use crate::sys::time::timer::TimerSpec; -pub use crate::sys::time::timer::{Expiration, TimerSetTimeFlags}; -use crate::time::ClockId; -use crate::{errno::Errno, Result}; -use core::mem; - -/// A Unix signal per-process timer. -#[derive(Debug)] -#[repr(transparent)] -pub struct Timer(libc::timer_t); - -impl Timer { - /// Creates a new timer based on the clock defined by `clockid`. The details - /// of the signal and its handler are defined by the passed `sigevent`. - #[doc(alias("timer_create"))] - pub fn new(clockid: ClockId, mut sigevent: SigEvent) -> Result<Self> { - let mut timer_id: mem::MaybeUninit<libc::timer_t> = - mem::MaybeUninit::uninit(); - Errno::result(unsafe { - libc::timer_create( - clockid.as_raw(), - sigevent.as_mut_ptr(), - timer_id.as_mut_ptr(), - ) - }) - .map(|_| { - // SAFETY: libc::timer_create is responsible for initializing - // timer_id. - unsafe { Self(timer_id.assume_init()) } - }) - } - - /// Set a new alarm on the timer. - /// - /// # Types of alarm - /// - /// There are 3 types of alarms you can set: - /// - /// - one shot: the alarm will trigger once after the specified amount of - /// time. - /// Example: I want an alarm to go off in 60s and then disable itself. - /// - /// - interval: the alarm will trigger every specified interval of time. - /// Example: I want an alarm to go off every 60s. The alarm will first - /// go off 60s after I set it and every 60s after that. The alarm will - /// not disable itself. - /// - /// - interval delayed: the alarm will trigger after a certain amount of - /// time and then trigger at a specified interval. - /// Example: I want an alarm to go off every 60s but only start in 1h. - /// The alarm will first trigger 1h after I set it and then every 60s - /// after that. The alarm will not disable itself. - /// - /// # Relative vs absolute alarm - /// - /// If you do not set any `TimerSetTimeFlags`, then the `TimeSpec` you pass - /// to the `Expiration` you want is relative. If however you want an alarm - /// to go off at a certain point in time, you can set `TFD_TIMER_ABSTIME`. - /// Then the one shot TimeSpec and the delay TimeSpec of the delayed - /// interval are going to be interpreted as absolute. - /// - /// # Disabling alarms - /// - /// Note: Only one alarm can be set for any given timer. Setting a new alarm - /// actually removes the previous one. - /// - /// Note: Setting a one shot alarm with a 0s TimeSpec disable the alarm - /// altogether. - #[doc(alias("timer_settime"))] - pub fn set( - &mut self, - expiration: Expiration, - flags: TimerSetTimeFlags, - ) -> Result<()> { - let timerspec: TimerSpec = expiration.into(); - Errno::result(unsafe { - libc::timer_settime( - self.0, - flags.bits(), - timerspec.as_ref(), - core::ptr::null_mut(), - ) - }) - .map(drop) - } - - /// Get the parameters for the alarm currently set, if any. - #[doc(alias("timer_gettime"))] - pub fn get(&self) -> Result<Option<Expiration>> { - let mut timerspec = TimerSpec::none(); - Errno::result(unsafe { - libc::timer_gettime(self.0, timerspec.as_mut()) - }) - .map(|_| { - if timerspec.as_ref().it_interval.tv_sec == 0 - && timerspec.as_ref().it_interval.tv_nsec == 0 - && timerspec.as_ref().it_value.tv_sec == 0 - && timerspec.as_ref().it_value.tv_nsec == 0 - { - None - } else { - Some(timerspec.into()) - } - }) - } - - /// Return the number of timers that have overrun - /// - /// Each timer is able to queue one signal to the process at a time, meaning - /// if the signal is not handled before the next expiration the timer has - /// 'overrun'. This function returns how many times that has happened to - /// this timer, up to `libc::DELAYTIMER_MAX`. If more than the maximum - /// number of overruns have happened the return is capped to the maximum. - #[doc(alias("timer_getoverrun"))] - pub fn overruns(&self) -> i32 { - unsafe { libc::timer_getoverrun(self.0) } - } -} - -impl Drop for Timer { - fn drop(&mut self) { - if !std::thread::panicking() { - let result = Errno::result(unsafe { libc::timer_delete(self.0) }); - if let Err(Errno::EINVAL) = result { - panic!("close of Timer encountered EINVAL"); - } - } - } -} diff --git a/vendor/nix/src/sys/timerfd.rs b/vendor/nix/src/sys/timerfd.rs deleted file mode 100644 index a35fc927f..000000000 --- a/vendor/nix/src/sys/timerfd.rs +++ /dev/null @@ -1,214 +0,0 @@ -//! Timer API via file descriptors. -//! -//! Timer FD is a Linux-only API to create timers and get expiration -//! notifications through file descriptors. -//! -//! For more documentation, please read [timerfd_create(2)](https://man7.org/linux/man-pages/man2/timerfd_create.2.html). -//! -//! # Examples -//! -//! Create a new one-shot timer that expires after 1 second. -//! ``` -//! # use std::os::unix::io::AsRawFd; -//! # use nix::sys::timerfd::{TimerFd, ClockId, TimerFlags, TimerSetTimeFlags, -//! # Expiration}; -//! # use nix::sys::time::{TimeSpec, TimeValLike}; -//! # use nix::unistd::read; -//! # -//! // We create a new monotonic timer. -//! let timer = TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()) -//! .unwrap(); -//! -//! // We set a new one-shot timer in 1 seconds. -//! timer.set( -//! Expiration::OneShot(TimeSpec::seconds(1)), -//! TimerSetTimeFlags::empty() -//! ).unwrap(); -//! -//! // We wait for the timer to expire. -//! timer.wait().unwrap(); -//! ``` -use crate::sys::time::timer::TimerSpec; -pub use crate::sys::time::timer::{Expiration, TimerSetTimeFlags}; -use crate::unistd::read; -use crate::{errno::Errno, Result}; -use libc::c_int; -use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; - -/// A timerfd instance. This is also a file descriptor, you can feed it to -/// other interfaces consuming file descriptors, epoll for example. -#[derive(Debug)] -pub struct TimerFd { - fd: RawFd, -} - -impl AsRawFd for TimerFd { - fn as_raw_fd(&self) -> RawFd { - self.fd - } -} - -impl FromRawFd for TimerFd { - unsafe fn from_raw_fd(fd: RawFd) -> Self { - TimerFd { fd } - } -} - -libc_enum! { - /// The type of the clock used to mark the progress of the timer. For more - /// details on each kind of clock, please refer to [timerfd_create(2)](https://man7.org/linux/man-pages/man2/timerfd_create.2.html). - #[repr(i32)] - #[non_exhaustive] - pub enum ClockId { - /// A settable system-wide real-time clock. - CLOCK_REALTIME, - /// A non-settable monotonically increasing clock. - /// - /// Does not change after system startup. - /// Does not measure time while the system is suspended. - CLOCK_MONOTONIC, - /// Like `CLOCK_MONOTONIC`, except that `CLOCK_BOOTTIME` includes the time - /// that the system was suspended. - CLOCK_BOOTTIME, - /// Like `CLOCK_REALTIME`, but will wake the system if it is suspended. - CLOCK_REALTIME_ALARM, - /// Like `CLOCK_BOOTTIME`, but will wake the system if it is suspended. - CLOCK_BOOTTIME_ALARM, - } -} - -libc_bitflags! { - /// Additional flags to change the behaviour of the file descriptor at the - /// time of creation. - pub struct TimerFlags: c_int { - /// Set the `O_NONBLOCK` flag on the open file description referred to by the new file descriptor. - TFD_NONBLOCK; - /// Set the `FD_CLOEXEC` flag on the file descriptor. - TFD_CLOEXEC; - } -} - -impl TimerFd { - /// Creates a new timer based on the clock defined by `clockid`. The - /// underlying fd can be assigned specific flags with `flags` (CLOEXEC, - /// NONBLOCK). The underlying fd will be closed on drop. - #[doc(alias("timerfd_create"))] - pub fn new(clockid: ClockId, flags: TimerFlags) -> Result<Self> { - Errno::result(unsafe { - libc::timerfd_create(clockid as i32, flags.bits()) - }) - .map(|fd| Self { fd }) - } - - /// Sets a new alarm on the timer. - /// - /// # Types of alarm - /// - /// There are 3 types of alarms you can set: - /// - /// - one shot: the alarm will trigger once after the specified amount of - /// time. - /// Example: I want an alarm to go off in 60s and then disable itself. - /// - /// - interval: the alarm will trigger every specified interval of time. - /// Example: I want an alarm to go off every 60s. The alarm will first - /// go off 60s after I set it and every 60s after that. The alarm will - /// not disable itself. - /// - /// - interval delayed: the alarm will trigger after a certain amount of - /// time and then trigger at a specified interval. - /// Example: I want an alarm to go off every 60s but only start in 1h. - /// The alarm will first trigger 1h after I set it and then every 60s - /// after that. The alarm will not disable itself. - /// - /// # Relative vs absolute alarm - /// - /// If you do not set any `TimerSetTimeFlags`, then the `TimeSpec` you pass - /// to the `Expiration` you want is relative. If however you want an alarm - /// to go off at a certain point in time, you can set `TFD_TIMER_ABSTIME`. - /// Then the one shot TimeSpec and the delay TimeSpec of the delayed - /// interval are going to be interpreted as absolute. - /// - /// # Disabling alarms - /// - /// Note: Only one alarm can be set for any given timer. Setting a new alarm - /// actually removes the previous one. - /// - /// Note: Setting a one shot alarm with a 0s TimeSpec disables the alarm - /// altogether. - #[doc(alias("timerfd_settime"))] - pub fn set( - &self, - expiration: Expiration, - flags: TimerSetTimeFlags, - ) -> Result<()> { - let timerspec: TimerSpec = expiration.into(); - Errno::result(unsafe { - libc::timerfd_settime( - self.fd, - flags.bits(), - timerspec.as_ref(), - std::ptr::null_mut(), - ) - }) - .map(drop) - } - - /// Get the parameters for the alarm currently set, if any. - #[doc(alias("timerfd_gettime"))] - pub fn get(&self) -> Result<Option<Expiration>> { - let mut timerspec = TimerSpec::none(); - Errno::result(unsafe { - libc::timerfd_gettime(self.fd, timerspec.as_mut()) - }) - .map(|_| { - if timerspec.as_ref().it_interval.tv_sec == 0 - && timerspec.as_ref().it_interval.tv_nsec == 0 - && timerspec.as_ref().it_value.tv_sec == 0 - && timerspec.as_ref().it_value.tv_nsec == 0 - { - None - } else { - Some(timerspec.into()) - } - }) - } - - /// Remove the alarm if any is set. - #[doc(alias("timerfd_settime"))] - pub fn unset(&self) -> Result<()> { - Errno::result(unsafe { - libc::timerfd_settime( - self.fd, - TimerSetTimeFlags::empty().bits(), - TimerSpec::none().as_ref(), - std::ptr::null_mut(), - ) - }) - .map(drop) - } - - /// Wait for the configured alarm to expire. - /// - /// Note: If the alarm is unset, then you will wait forever. - pub fn wait(&self) -> Result<()> { - while let Err(e) = read(self.fd, &mut [0u8; 8]) { - if e != Errno::EINTR { - return Err(e); - } - } - - Ok(()) - } -} - -impl Drop for TimerFd { - fn drop(&mut self) { - if !std::thread::panicking() { - let result = Errno::result(unsafe { libc::close(self.fd) }); - if let Err(Errno::EBADF) = result { - panic!("close of TimerFd encountered EBADF"); - } - } - } -} diff --git a/vendor/nix/src/sys/uio.rs b/vendor/nix/src/sys/uio.rs deleted file mode 100644 index b31c3068a..000000000 --- a/vendor/nix/src/sys/uio.rs +++ /dev/null @@ -1,291 +0,0 @@ -//! Vectored I/O - -use crate::errno::Errno; -use crate::Result; -use libc::{self, c_int, c_void, off_t, size_t}; -use std::io::{IoSlice, IoSliceMut}; -use std::marker::PhantomData; -use std::os::unix::io::RawFd; - -/// Low-level vectored write to a raw file descriptor -/// -/// See also [writev(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/writev.html) -pub fn writev(fd: RawFd, iov: &[IoSlice<'_>]) -> Result<usize> { - // SAFETY: to quote the documentation for `IoSlice`: - // - // [IoSlice] is semantically a wrapper around a &[u8], but is - // guaranteed to be ABI compatible with the iovec type on Unix - // platforms. - // - // Because it is ABI compatible, a pointer cast here is valid - let res = unsafe { - libc::writev(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int) - }; - - Errno::result(res).map(|r| r as usize) -} - -/// Low-level vectored read from a raw file descriptor -/// -/// See also [readv(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/readv.html) -pub fn readv(fd: RawFd, iov: &mut [IoSliceMut<'_>]) -> Result<usize> { - // SAFETY: same as in writev(), IoSliceMut is ABI-compatible with iovec - let res = unsafe { - libc::readv(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int) - }; - - Errno::result(res).map(|r| r as usize) -} - -/// Write to `fd` at `offset` from buffers in `iov`. -/// -/// Buffers in `iov` will be written in order until all buffers have been written -/// or an error occurs. The file offset is not changed. -/// -/// See also: [`writev`](fn.writev.html) and [`pwrite`](fn.pwrite.html) -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub fn pwritev(fd: RawFd, iov: &[IoSlice<'_>], offset: off_t) -> Result<usize> { - #[cfg(target_env = "uclibc")] - let offset = offset as libc::off64_t; // uclibc doesn't use off_t - - // SAFETY: same as in writev() - let res = unsafe { - libc::pwritev( - fd, - iov.as_ptr() as *const libc::iovec, - iov.len() as c_int, - offset, - ) - }; - - Errno::result(res).map(|r| r as usize) -} - -/// Read from `fd` at `offset` filling buffers in `iov`. -/// -/// Buffers in `iov` will be filled in order until all buffers have been filled, -/// no more bytes are available, or an error occurs. The file offset is not -/// changed. -/// -/// See also: [`readv`](fn.readv.html) and [`pread`](fn.pread.html) -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub fn preadv( - fd: RawFd, - iov: &mut [IoSliceMut<'_>], - offset: off_t, -) -> Result<usize> { - #[cfg(target_env = "uclibc")] - let offset = offset as libc::off64_t; // uclibc doesn't use off_t - - // SAFETY: same as in readv() - let res = unsafe { - libc::preadv( - fd, - iov.as_ptr() as *const libc::iovec, - iov.len() as c_int, - offset, - ) - }; - - Errno::result(res).map(|r| r as usize) -} - -/// Low-level write to a file, with specified offset. -/// -/// See also [pwrite(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pwrite.html) -// TODO: move to unistd -pub fn pwrite(fd: RawFd, buf: &[u8], offset: off_t) -> Result<usize> { - let res = unsafe { - libc::pwrite( - fd, - buf.as_ptr() as *const c_void, - buf.len() as size_t, - offset, - ) - }; - - Errno::result(res).map(|r| r as usize) -} - -/// Low-level read from a file, with specified offset. -/// -/// See also [pread(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pread.html) -// TODO: move to unistd -pub fn pread(fd: RawFd, buf: &mut [u8], offset: off_t) -> Result<usize> { - let res = unsafe { - libc::pread( - fd, - buf.as_mut_ptr() as *mut c_void, - buf.len() as size_t, - offset, - ) - }; - - Errno::result(res).map(|r| r as usize) -} - -/// A slice of memory in a remote process, starting at address `base` -/// and consisting of `len` bytes. -/// -/// This is the same underlying C structure as `IoSlice`, -/// except that it refers to memory in some other process, and is -/// therefore not represented in Rust by an actual slice as `IoSlice` is. It -/// is used with [`process_vm_readv`](fn.process_vm_readv.html) -/// and [`process_vm_writev`](fn.process_vm_writev.html). -#[cfg(any(target_os = "linux", target_os = "android"))] -#[cfg_attr(docsrs, doc(cfg(all())))] -#[repr(C)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct RemoteIoVec { - /// The starting address of this slice (`iov_base`). - pub base: usize, - /// The number of bytes in this slice (`iov_len`). - pub len: usize, -} - -/// A vector of buffers. -/// -/// Vectored I/O methods like [`writev`] and [`readv`] use this structure for -/// both reading and writing. Each `IoVec` specifies the base address and -/// length of an area in memory. -#[deprecated( - since = "0.24.0", - note = "`IoVec` is no longer used in the public interface, use `IoSlice` or `IoSliceMut` instead" -)] -#[repr(transparent)] -#[allow(renamed_and_removed_lints)] -#[allow(clippy::unknown_clippy_lints)] -// Clippy false positive: https://github.com/rust-lang/rust-clippy/issues/8867 -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct IoVec<T>(pub(crate) libc::iovec, PhantomData<T>); - -#[allow(deprecated)] -impl<T> IoVec<T> { - /// View the `IoVec` as a Rust slice. - #[deprecated( - since = "0.24.0", - note = "Use the `Deref` impl of `IoSlice` or `IoSliceMut` instead" - )] - #[inline] - pub fn as_slice(&self) -> &[u8] { - use std::slice; - - unsafe { - slice::from_raw_parts(self.0.iov_base as *const u8, self.0.iov_len) - } - } -} - -#[allow(deprecated)] -impl<'a> IoVec<&'a [u8]> { - /// Create an `IoVec` from a Rust slice. - #[deprecated(since = "0.24.0", note = "Use `IoSlice::new` instead")] - pub fn from_slice(buf: &'a [u8]) -> IoVec<&'a [u8]> { - IoVec( - libc::iovec { - iov_base: buf.as_ptr() as *mut c_void, - iov_len: buf.len() as size_t, - }, - PhantomData, - ) - } -} - -#[allow(deprecated)] -impl<'a> IoVec<&'a mut [u8]> { - /// Create an `IoVec` from a mutable Rust slice. - #[deprecated(since = "0.24.0", note = "Use `IoSliceMut::new` instead")] - pub fn from_mut_slice(buf: &'a mut [u8]) -> IoVec<&'a mut [u8]> { - IoVec( - libc::iovec { - iov_base: buf.as_ptr() as *mut c_void, - iov_len: buf.len() as size_t, - }, - PhantomData, - ) - } -} - -// The only reason IoVec isn't automatically Send+Sync is because libc::iovec -// contains raw pointers. -#[allow(deprecated)] -unsafe impl<T> Send for IoVec<T> where T: Send {} -#[allow(deprecated)] -unsafe impl<T> Sync for IoVec<T> where T: Sync {} - -feature! { -#![feature = "process"] - -/// Write data directly to another process's virtual memory -/// (see [`process_vm_writev`(2)]). -/// -/// `local_iov` is a list of [`IoSlice`]s containing the data to be written, -/// and `remote_iov` is a list of [`RemoteIoVec`]s identifying where the -/// data should be written in the target process. On success, returns the -/// number of bytes written, which will always be a whole -/// number of `remote_iov` chunks. -/// -/// This requires the same permissions as debugging the process using -/// [ptrace]: you must either be a privileged process (with -/// `CAP_SYS_PTRACE`), or you must be running as the same user as the -/// target process and the OS must have unprivileged debugging enabled. -/// -/// This function is only available on Linux and Android(SDK23+). -/// -/// [`process_vm_writev`(2)]: https://man7.org/linux/man-pages/man2/process_vm_writev.2.html -/// [ptrace]: ../ptrace/index.html -/// [`IoSlice`]: https://doc.rust-lang.org/std/io/struct.IoSlice.html -/// [`RemoteIoVec`]: struct.RemoteIoVec.html -#[cfg(all(any(target_os = "linux", target_os = "android"), not(target_env = "uclibc")))] -pub fn process_vm_writev( - pid: crate::unistd::Pid, - local_iov: &[IoSlice<'_>], - remote_iov: &[RemoteIoVec]) -> Result<usize> -{ - let res = unsafe { - libc::process_vm_writev(pid.into(), - local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong, - remote_iov.as_ptr() as *const libc::iovec, remote_iov.len() as libc::c_ulong, 0) - }; - - Errno::result(res).map(|r| r as usize) -} - -/// Read data directly from another process's virtual memory -/// (see [`process_vm_readv`(2)]). -/// -/// `local_iov` is a list of [`IoSliceMut`]s containing the buffer to copy -/// data into, and `remote_iov` is a list of [`RemoteIoVec`]s identifying -/// where the source data is in the target process. On success, -/// returns the number of bytes written, which will always be a whole -/// number of `remote_iov` chunks. -/// -/// This requires the same permissions as debugging the process using -/// [`ptrace`]: you must either be a privileged process (with -/// `CAP_SYS_PTRACE`), or you must be running as the same user as the -/// target process and the OS must have unprivileged debugging enabled. -/// -/// This function is only available on Linux and Android(SDK23+). -/// -/// [`process_vm_readv`(2)]: https://man7.org/linux/man-pages/man2/process_vm_readv.2.html -/// [`ptrace`]: ../ptrace/index.html -/// [`IoSliceMut`]: https://doc.rust-lang.org/std/io/struct.IoSliceMut.html -/// [`RemoteIoVec`]: struct.RemoteIoVec.html -#[cfg(all(any(target_os = "linux", target_os = "android"), not(target_env = "uclibc")))] -pub fn process_vm_readv( - pid: crate::unistd::Pid, - local_iov: &mut [IoSliceMut<'_>], - remote_iov: &[RemoteIoVec]) -> Result<usize> -{ - let res = unsafe { - libc::process_vm_readv(pid.into(), - local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong, - remote_iov.as_ptr() as *const libc::iovec, remote_iov.len() as libc::c_ulong, 0) - }; - - Errno::result(res).map(|r| r as usize) -} -} diff --git a/vendor/nix/src/sys/utsname.rs b/vendor/nix/src/sys/utsname.rs deleted file mode 100644 index b48ed9f45..000000000 --- a/vendor/nix/src/sys/utsname.rs +++ /dev/null @@ -1,85 +0,0 @@ -//! Get system identification -use crate::{Errno, Result}; -use libc::c_char; -use std::ffi::OsStr; -use std::mem; -use std::os::unix::ffi::OsStrExt; - -/// Describes the running system. Return type of [`uname`]. -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -#[repr(transparent)] -pub struct UtsName(libc::utsname); - -impl UtsName { - /// Name of the operating system implementation. - pub fn sysname(&self) -> &OsStr { - cast_and_trim(&self.0.sysname) - } - - /// Network name of this machine. - pub fn nodename(&self) -> &OsStr { - cast_and_trim(&self.0.nodename) - } - - /// Release level of the operating system. - pub fn release(&self) -> &OsStr { - cast_and_trim(&self.0.release) - } - - /// Version level of the operating system. - pub fn version(&self) -> &OsStr { - cast_and_trim(&self.0.version) - } - - /// Machine hardware platform. - pub fn machine(&self) -> &OsStr { - cast_and_trim(&self.0.machine) - } - - /// NIS or YP domain name of this machine. - #[cfg(any(target_os = "android", target_os = "linux"))] - pub fn domainname(&self) -> &OsStr { - cast_and_trim(&self.0.domainname) - } -} - -/// Get system identification -pub fn uname() -> Result<UtsName> { - unsafe { - let mut ret = mem::MaybeUninit::zeroed(); - Errno::result(libc::uname(ret.as_mut_ptr()))?; - Ok(UtsName(ret.assume_init())) - } -} - -fn cast_and_trim(slice: &[c_char]) -> &OsStr { - let length = slice - .iter() - .position(|&byte| byte == 0) - .unwrap_or(slice.len()); - let bytes = - unsafe { std::slice::from_raw_parts(slice.as_ptr().cast(), length) }; - - OsStr::from_bytes(bytes) -} - -#[cfg(test)] -mod test { - #[cfg(target_os = "linux")] - #[test] - pub fn test_uname_linux() { - assert_eq!(super::uname().unwrap().sysname(), "Linux"); - } - - #[cfg(any(target_os = "macos", target_os = "ios"))] - #[test] - pub fn test_uname_darwin() { - assert_eq!(super::uname().unwrap().sysname(), "Darwin"); - } - - #[cfg(target_os = "freebsd")] - #[test] - pub fn test_uname_freebsd() { - assert_eq!(super::uname().unwrap().sysname(), "FreeBSD"); - } -} diff --git a/vendor/nix/src/sys/wait.rs b/vendor/nix/src/sys/wait.rs deleted file mode 100644 index b6524e866..000000000 --- a/vendor/nix/src/sys/wait.rs +++ /dev/null @@ -1,388 +0,0 @@ -//! Wait for a process to change status -use crate::errno::Errno; -use crate::sys::signal::Signal; -use crate::unistd::Pid; -use crate::Result; -use cfg_if::cfg_if; -use libc::{self, c_int}; -use std::convert::TryFrom; -#[cfg(any( - target_os = "android", - all(target_os = "linux", not(target_env = "uclibc")), -))] -use std::os::unix::io::RawFd; - -libc_bitflags!( - /// Controls the behavior of [`waitpid`]. - pub struct WaitPidFlag: c_int { - /// Do not block when there are no processes wishing to report status. - WNOHANG; - /// Report the status of selected processes which are stopped due to a - /// [`SIGTTIN`](crate::sys::signal::Signal::SIGTTIN), - /// [`SIGTTOU`](crate::sys::signal::Signal::SIGTTOU), - /// [`SIGTSTP`](crate::sys::signal::Signal::SIGTSTP), or - /// [`SIGSTOP`](crate::sys::signal::Signal::SIGSTOP) signal. - WUNTRACED; - /// Report the status of selected processes which have terminated. - #[cfg(any(target_os = "android", - target_os = "freebsd", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "redox", - target_os = "macos", - target_os = "netbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - WEXITED; - /// Report the status of selected processes that have continued from a - /// job control stop by receiving a - /// [`SIGCONT`](crate::sys::signal::Signal::SIGCONT) signal. - WCONTINUED; - /// An alias for WUNTRACED. - #[cfg(any(target_os = "android", - target_os = "freebsd", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "redox", - target_os = "macos", - target_os = "netbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - WSTOPPED; - /// Don't reap, just poll status. - #[cfg(any(target_os = "android", - target_os = "freebsd", - target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "redox", - target_os = "macos", - target_os = "netbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - WNOWAIT; - /// Don't wait on children of other threads in this group - #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - __WNOTHREAD; - /// Wait on all children, regardless of type - #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - __WALL; - /// Wait for "clone" children only. - #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - __WCLONE; - } -); - -/// Possible return values from `wait()` or `waitpid()`. -/// -/// Each status (other than `StillAlive`) describes a state transition -/// in a child process `Pid`, such as the process exiting or stopping, -/// plus additional data about the transition if any. -/// -/// Note that there are two Linux-specific enum variants, `PtraceEvent` -/// and `PtraceSyscall`. Portable code should avoid exhaustively -/// matching on `WaitStatus`. -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum WaitStatus { - /// The process exited normally (as with `exit()` or returning from - /// `main`) with the given exit code. This case matches the C macro - /// `WIFEXITED(status)`; the second field is `WEXITSTATUS(status)`. - Exited(Pid, i32), - /// The process was killed by the given signal. The third field - /// indicates whether the signal generated a core dump. This case - /// matches the C macro `WIFSIGNALED(status)`; the last two fields - /// correspond to `WTERMSIG(status)` and `WCOREDUMP(status)`. - Signaled(Pid, Signal, bool), - /// The process is alive, but was stopped by the given signal. This - /// is only reported if `WaitPidFlag::WUNTRACED` was passed. This - /// case matches the C macro `WIFSTOPPED(status)`; the second field - /// is `WSTOPSIG(status)`. - Stopped(Pid, Signal), - /// The traced process was stopped by a `PTRACE_EVENT_*` event. See - /// [`nix::sys::ptrace`] and [`ptrace`(2)] for more information. All - /// currently-defined events use `SIGTRAP` as the signal; the third - /// field is the `PTRACE_EVENT_*` value of the event. - /// - /// [`nix::sys::ptrace`]: ../ptrace/index.html - /// [`ptrace`(2)]: https://man7.org/linux/man-pages/man2/ptrace.2.html - #[cfg(any(target_os = "linux", target_os = "android"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - PtraceEvent(Pid, Signal, c_int), - /// The traced process was stopped by execution of a system call, - /// and `PTRACE_O_TRACESYSGOOD` is in effect. See [`ptrace`(2)] for - /// more information. - /// - /// [`ptrace`(2)]: https://man7.org/linux/man-pages/man2/ptrace.2.html - #[cfg(any(target_os = "linux", target_os = "android"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - PtraceSyscall(Pid), - /// The process was previously stopped but has resumed execution - /// after receiving a `SIGCONT` signal. This is only reported if - /// `WaitPidFlag::WCONTINUED` was passed. This case matches the C - /// macro `WIFCONTINUED(status)`. - Continued(Pid), - /// There are currently no state changes to report in any awaited - /// child process. This is only returned if `WaitPidFlag::WNOHANG` - /// was used (otherwise `wait()` or `waitpid()` would block until - /// there was something to report). - StillAlive, -} - -impl WaitStatus { - /// Extracts the PID from the WaitStatus unless it equals StillAlive. - pub fn pid(&self) -> Option<Pid> { - use self::WaitStatus::*; - match *self { - Exited(p, _) | Signaled(p, _, _) | Stopped(p, _) | Continued(p) => { - Some(p) - } - StillAlive => None, - #[cfg(any(target_os = "android", target_os = "linux"))] - PtraceEvent(p, _, _) | PtraceSyscall(p) => Some(p), - } - } -} - -fn exited(status: i32) -> bool { - libc::WIFEXITED(status) -} - -fn exit_status(status: i32) -> i32 { - libc::WEXITSTATUS(status) -} - -fn signaled(status: i32) -> bool { - libc::WIFSIGNALED(status) -} - -fn term_signal(status: i32) -> Result<Signal> { - Signal::try_from(libc::WTERMSIG(status)) -} - -fn dumped_core(status: i32) -> bool { - libc::WCOREDUMP(status) -} - -fn stopped(status: i32) -> bool { - libc::WIFSTOPPED(status) -} - -fn stop_signal(status: i32) -> Result<Signal> { - Signal::try_from(libc::WSTOPSIG(status)) -} - -#[cfg(any(target_os = "android", target_os = "linux"))] -fn syscall_stop(status: i32) -> bool { - // From ptrace(2), setting PTRACE_O_TRACESYSGOOD has the effect - // of delivering SIGTRAP | 0x80 as the signal number for syscall - // stops. This allows easily distinguishing syscall stops from - // genuine SIGTRAP signals. - libc::WSTOPSIG(status) == libc::SIGTRAP | 0x80 -} - -#[cfg(any(target_os = "android", target_os = "linux"))] -fn stop_additional(status: i32) -> c_int { - (status >> 16) as c_int -} - -fn continued(status: i32) -> bool { - libc::WIFCONTINUED(status) -} - -impl WaitStatus { - /// Convert a raw `wstatus` as returned by `waitpid`/`wait` into a `WaitStatus` - /// - /// # Errors - /// - /// Returns an `Error` corresponding to `EINVAL` for invalid status values. - /// - /// # Examples - /// - /// Convert a `wstatus` obtained from `libc::waitpid` into a `WaitStatus`: - /// - /// ``` - /// use nix::sys::wait::WaitStatus; - /// use nix::sys::signal::Signal; - /// let pid = nix::unistd::Pid::from_raw(1); - /// let status = WaitStatus::from_raw(pid, 0x0002); - /// assert_eq!(status, Ok(WaitStatus::Signaled(pid, Signal::SIGINT, false))); - /// ``` - pub fn from_raw(pid: Pid, status: i32) -> Result<WaitStatus> { - Ok(if exited(status) { - WaitStatus::Exited(pid, exit_status(status)) - } else if signaled(status) { - WaitStatus::Signaled(pid, term_signal(status)?, dumped_core(status)) - } else if stopped(status) { - cfg_if! { - if #[cfg(any(target_os = "android", target_os = "linux"))] { - fn decode_stopped(pid: Pid, status: i32) -> Result<WaitStatus> { - let status_additional = stop_additional(status); - Ok(if syscall_stop(status) { - WaitStatus::PtraceSyscall(pid) - } else if status_additional == 0 { - WaitStatus::Stopped(pid, stop_signal(status)?) - } else { - WaitStatus::PtraceEvent(pid, stop_signal(status)?, - stop_additional(status)) - }) - } - } else { - fn decode_stopped(pid: Pid, status: i32) -> Result<WaitStatus> { - Ok(WaitStatus::Stopped(pid, stop_signal(status)?)) - } - } - } - return decode_stopped(pid, status); - } else { - assert!(continued(status)); - WaitStatus::Continued(pid) - }) - } - - /// Convert a `siginfo_t` as returned by `waitid` to a `WaitStatus` - /// - /// # Errors - /// - /// Returns an `Error` corresponding to `EINVAL` for invalid values. - /// - /// # Safety - /// - /// siginfo_t is actually a union, not all fields may be initialized. - /// The functions si_pid() and si_status() must be valid to call on - /// the passed siginfo_t. - #[cfg(any( - target_os = "android", - target_os = "freebsd", - target_os = "haiku", - all(target_os = "linux", not(target_env = "uclibc")), - ))] - unsafe fn from_siginfo(siginfo: &libc::siginfo_t) -> Result<WaitStatus> { - let si_pid = siginfo.si_pid(); - if si_pid == 0 { - return Ok(WaitStatus::StillAlive); - } - - assert_eq!(siginfo.si_signo, libc::SIGCHLD); - - let pid = Pid::from_raw(si_pid); - let si_status = siginfo.si_status(); - - let status = match siginfo.si_code { - libc::CLD_EXITED => WaitStatus::Exited(pid, si_status), - libc::CLD_KILLED | libc::CLD_DUMPED => WaitStatus::Signaled( - pid, - Signal::try_from(si_status)?, - siginfo.si_code == libc::CLD_DUMPED, - ), - libc::CLD_STOPPED => { - WaitStatus::Stopped(pid, Signal::try_from(si_status)?) - } - libc::CLD_CONTINUED => WaitStatus::Continued(pid), - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::CLD_TRAPPED => { - if si_status == libc::SIGTRAP | 0x80 { - WaitStatus::PtraceSyscall(pid) - } else { - WaitStatus::PtraceEvent( - pid, - Signal::try_from(si_status & 0xff)?, - (si_status >> 8) as c_int, - ) - } - } - _ => return Err(Errno::EINVAL), - }; - - Ok(status) - } -} - -/// Wait for a process to change status -/// -/// See also [waitpid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/waitpid.html) -pub fn waitpid<P: Into<Option<Pid>>>( - pid: P, - options: Option<WaitPidFlag>, -) -> Result<WaitStatus> { - use self::WaitStatus::*; - - let mut status: i32 = 0; - - let option_bits = match options { - Some(bits) => bits.bits(), - None => 0, - }; - - let res = unsafe { - libc::waitpid( - pid.into().unwrap_or_else(|| Pid::from_raw(-1)).into(), - &mut status as *mut c_int, - option_bits, - ) - }; - - match Errno::result(res)? { - 0 => Ok(StillAlive), - res => WaitStatus::from_raw(Pid::from_raw(res), status), - } -} - -/// Wait for any child process to change status or a signal is received. -/// -/// See also [wait(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html) -pub fn wait() -> Result<WaitStatus> { - waitpid(None, None) -} - -/// The ID argument for `waitid` -#[cfg(any( - target_os = "android", - target_os = "freebsd", - target_os = "haiku", - all(target_os = "linux", not(target_env = "uclibc")), -))] -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum Id { - /// Wait for any child - All, - /// Wait for the child whose process ID matches the given PID - Pid(Pid), - /// Wait for the child whose process group ID matches the given PID - /// - /// If the PID is zero, the caller's process group is used since Linux 5.4. - PGid(Pid), - /// Wait for the child referred to by the given PID file descriptor - #[cfg(any(target_os = "android", target_os = "linux"))] - PIDFd(RawFd), -} - -/// Wait for a process to change status -/// -/// See also [waitid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/waitid.html) -#[cfg(any( - target_os = "android", - target_os = "freebsd", - target_os = "haiku", - all(target_os = "linux", not(target_env = "uclibc")), -))] -pub fn waitid(id: Id, flags: WaitPidFlag) -> Result<WaitStatus> { - let (idtype, idval) = match id { - Id::All => (libc::P_ALL, 0), - Id::Pid(pid) => (libc::P_PID, pid.as_raw() as libc::id_t), - Id::PGid(pid) => (libc::P_PGID, pid.as_raw() as libc::id_t), - #[cfg(any(target_os = "android", target_os = "linux"))] - Id::PIDFd(fd) => (libc::P_PIDFD, fd as libc::id_t), - }; - - let siginfo = unsafe { - // Memory is zeroed rather than uninitialized, as not all platforms - // initialize the memory in the StillAlive case - let mut siginfo: libc::siginfo_t = std::mem::zeroed(); - Errno::result(libc::waitid(idtype, idval, &mut siginfo, flags.bits()))?; - siginfo - }; - - unsafe { WaitStatus::from_siginfo(&siginfo) } -} diff --git a/vendor/nix/src/time.rs b/vendor/nix/src/time.rs deleted file mode 100644 index 2e03c46cf..000000000 --- a/vendor/nix/src/time.rs +++ /dev/null @@ -1,283 +0,0 @@ -use crate::sys::time::TimeSpec; -#[cfg(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "linux", - target_os = "android", - target_os = "emscripten", -))] -#[cfg(feature = "process")] -use crate::unistd::Pid; -use crate::{Errno, Result}; -use libc::{self, clockid_t}; -use std::mem::MaybeUninit; - -/// Clock identifier -/// -/// Newtype pattern around `clockid_t` (which is just alias). It prevents bugs caused by -/// accidentally passing wrong value. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] -pub struct ClockId(clockid_t); - -impl ClockId { - /// Creates `ClockId` from raw `clockid_t` - pub const fn from_raw(clk_id: clockid_t) -> Self { - ClockId(clk_id) - } - - feature! { - #![feature = "process"] - /// Returns `ClockId` of a `pid` CPU-time clock - #[cfg(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "linux", - target_os = "android", - target_os = "emscripten", - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn pid_cpu_clock_id(pid: Pid) -> Result<Self> { - clock_getcpuclockid(pid) - } - } - - /// Returns resolution of the clock id - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn res(self) -> Result<TimeSpec> { - clock_getres(self) - } - - /// Returns the current time on the clock id - pub fn now(self) -> Result<TimeSpec> { - clock_gettime(self) - } - - /// Sets time to `timespec` on the clock id - #[cfg(not(any( - target_os = "macos", - target_os = "ios", - target_os = "redox", - target_os = "hermit", - )))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn set_time(self, timespec: TimeSpec) -> Result<()> { - clock_settime(self, timespec) - } - - /// Gets the raw `clockid_t` wrapped by `self` - pub const fn as_raw(self) -> clockid_t { - self.0 - } - - #[cfg(any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "linux" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub const CLOCK_BOOTTIME: ClockId = ClockId(libc::CLOCK_BOOTTIME); - #[cfg(any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "linux" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub const CLOCK_BOOTTIME_ALARM: ClockId = - ClockId(libc::CLOCK_BOOTTIME_ALARM); - pub const CLOCK_MONOTONIC: ClockId = ClockId(libc::CLOCK_MONOTONIC); - #[cfg(any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "linux" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub const CLOCK_MONOTONIC_COARSE: ClockId = - ClockId(libc::CLOCK_MONOTONIC_COARSE); - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub const CLOCK_MONOTONIC_FAST: ClockId = - ClockId(libc::CLOCK_MONOTONIC_FAST); - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub const CLOCK_MONOTONIC_PRECISE: ClockId = - ClockId(libc::CLOCK_MONOTONIC_PRECISE); - #[cfg(any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "linux" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub const CLOCK_MONOTONIC_RAW: ClockId = ClockId(libc::CLOCK_MONOTONIC_RAW); - #[cfg(any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "redox", - target_os = "linux" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub const CLOCK_PROCESS_CPUTIME_ID: ClockId = - ClockId(libc::CLOCK_PROCESS_CPUTIME_ID); - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub const CLOCK_PROF: ClockId = ClockId(libc::CLOCK_PROF); - pub const CLOCK_REALTIME: ClockId = ClockId(libc::CLOCK_REALTIME); - #[cfg(any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "linux" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub const CLOCK_REALTIME_ALARM: ClockId = - ClockId(libc::CLOCK_REALTIME_ALARM); - #[cfg(any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "linux" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub const CLOCK_REALTIME_COARSE: ClockId = - ClockId(libc::CLOCK_REALTIME_COARSE); - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub const CLOCK_REALTIME_FAST: ClockId = ClockId(libc::CLOCK_REALTIME_FAST); - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub const CLOCK_REALTIME_PRECISE: ClockId = - ClockId(libc::CLOCK_REALTIME_PRECISE); - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub const CLOCK_SECOND: ClockId = ClockId(libc::CLOCK_SECOND); - #[cfg(any( - target_os = "emscripten", - target_os = "fuchsia", - all(target_os = "linux", target_env = "musl") - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub const CLOCK_SGI_CYCLE: ClockId = ClockId(libc::CLOCK_SGI_CYCLE); - #[cfg(any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "linux" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub const CLOCK_TAI: ClockId = ClockId(libc::CLOCK_TAI); - #[cfg(any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "ios", - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "linux" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub const CLOCK_THREAD_CPUTIME_ID: ClockId = - ClockId(libc::CLOCK_THREAD_CPUTIME_ID); - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub const CLOCK_UPTIME: ClockId = ClockId(libc::CLOCK_UPTIME); - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub const CLOCK_UPTIME_FAST: ClockId = ClockId(libc::CLOCK_UPTIME_FAST); - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub const CLOCK_UPTIME_PRECISE: ClockId = - ClockId(libc::CLOCK_UPTIME_PRECISE); - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub const CLOCK_VIRTUAL: ClockId = ClockId(libc::CLOCK_VIRTUAL); -} - -impl From<ClockId> for clockid_t { - fn from(clock_id: ClockId) -> Self { - clock_id.as_raw() - } -} - -impl From<clockid_t> for ClockId { - fn from(clk_id: clockid_t) -> Self { - ClockId::from_raw(clk_id) - } -} - -impl std::fmt::Display for ClockId { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - std::fmt::Display::fmt(&self.0, f) - } -} - -/// Get the resolution of the specified clock, (see -/// [clock_getres(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_getres.html)). -#[cfg(not(target_os = "redox"))] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub fn clock_getres(clock_id: ClockId) -> Result<TimeSpec> { - let mut c_time: MaybeUninit<libc::timespec> = MaybeUninit::uninit(); - let ret = - unsafe { libc::clock_getres(clock_id.as_raw(), c_time.as_mut_ptr()) }; - Errno::result(ret)?; - let res = unsafe { c_time.assume_init() }; - Ok(TimeSpec::from(res)) -} - -/// Get the time of the specified clock, (see -/// [clock_gettime(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_gettime.html)). -pub fn clock_gettime(clock_id: ClockId) -> Result<TimeSpec> { - let mut c_time: MaybeUninit<libc::timespec> = MaybeUninit::uninit(); - let ret = - unsafe { libc::clock_gettime(clock_id.as_raw(), c_time.as_mut_ptr()) }; - Errno::result(ret)?; - let res = unsafe { c_time.assume_init() }; - Ok(TimeSpec::from(res)) -} - -/// Set the time of the specified clock, (see -/// [clock_settime(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_settime.html)). -#[cfg(not(any( - target_os = "macos", - target_os = "ios", - target_os = "redox", - target_os = "hermit", -)))] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub fn clock_settime(clock_id: ClockId, timespec: TimeSpec) -> Result<()> { - let ret = - unsafe { libc::clock_settime(clock_id.as_raw(), timespec.as_ref()) }; - Errno::result(ret).map(drop) -} - -/// Get the clock id of the specified process id, (see -/// [clock_getcpuclockid(3)](https://pubs.opengroup.org/onlinepubs/009695399/functions/clock_getcpuclockid.html)). -#[cfg(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "linux", - target_os = "android", - target_os = "emscripten", -))] -#[cfg(feature = "process")] -#[cfg_attr(docsrs, doc(cfg(feature = "process")))] -pub fn clock_getcpuclockid(pid: Pid) -> Result<ClockId> { - let mut clk_id: MaybeUninit<libc::clockid_t> = MaybeUninit::uninit(); - let ret = - unsafe { libc::clock_getcpuclockid(pid.into(), clk_id.as_mut_ptr()) }; - if ret == 0 { - let res = unsafe { clk_id.assume_init() }; - Ok(ClockId::from(res)) - } else { - Err(Errno::from_i32(ret)) - } -} diff --git a/vendor/nix/src/ucontext.rs b/vendor/nix/src/ucontext.rs deleted file mode 100644 index b2a39f769..000000000 --- a/vendor/nix/src/ucontext.rs +++ /dev/null @@ -1,47 +0,0 @@ -#[cfg(not(target_env = "musl"))] -use crate::errno::Errno; -use crate::sys::signal::SigSet; -#[cfg(not(target_env = "musl"))] -use crate::Result; -#[cfg(not(target_env = "musl"))] -use std::mem; - -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct UContext { - context: libc::ucontext_t, -} - -impl UContext { - #[cfg(not(target_env = "musl"))] - pub fn get() -> Result<UContext> { - let mut context = mem::MaybeUninit::<libc::ucontext_t>::uninit(); - let res = unsafe { libc::getcontext(context.as_mut_ptr()) }; - Errno::result(res).map(|_| unsafe { - UContext { - context: context.assume_init(), - } - }) - } - - #[cfg(not(target_env = "musl"))] - pub fn set(&self) -> Result<()> { - let res = unsafe { - libc::setcontext(&self.context as *const libc::ucontext_t) - }; - Errno::result(res).map(drop) - } - - pub fn sigmask_mut(&mut self) -> &mut SigSet { - unsafe { - &mut *(&mut self.context.uc_sigmask as *mut libc::sigset_t - as *mut SigSet) - } - } - - pub fn sigmask(&self) -> &SigSet { - unsafe { - &*(&self.context.uc_sigmask as *const libc::sigset_t - as *const SigSet) - } - } -} diff --git a/vendor/nix/src/unistd.rs b/vendor/nix/src/unistd.rs deleted file mode 100644 index ca07b34a2..000000000 --- a/vendor/nix/src/unistd.rs +++ /dev/null @@ -1,3383 +0,0 @@ -//! Safe wrappers around functions found in libc "unistd.h" header - -use crate::errno::{self, Errno}; -#[cfg(not(target_os = "redox"))] -#[cfg(feature = "fs")] -use crate::fcntl::{at_rawfd, AtFlags}; -#[cfg(feature = "fs")] -use crate::fcntl::{fcntl, FcntlArg::F_SETFD, FdFlag, OFlag}; -#[cfg(all( - feature = "fs", - any( - target_os = "openbsd", - target_os = "netbsd", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "macos", - target_os = "ios" - ) -))] -use crate::sys::stat::FileFlag; -#[cfg(feature = "fs")] -use crate::sys::stat::Mode; -use crate::{Error, NixPath, Result}; -#[cfg(not(target_os = "redox"))] -use cfg_if::cfg_if; -use libc::{ - self, c_char, c_int, c_long, c_uint, c_void, gid_t, mode_t, off_t, pid_t, - size_t, uid_t, PATH_MAX, -}; -use std::convert::Infallible; -use std::ffi::{CStr, OsString}; -#[cfg(not(target_os = "redox"))] -use std::ffi::{CString, OsStr}; -#[cfg(not(target_os = "redox"))] -use std::os::unix::ffi::OsStrExt; -use std::os::unix::ffi::OsStringExt; -use std::os::unix::io::RawFd; -use std::path::PathBuf; -use std::{fmt, mem, ptr}; - -feature! { - #![feature = "fs"] - #[cfg(any(target_os = "android", target_os = "linux"))] - pub use self::pivot_root::*; -} - -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd" -))] -pub use self::setres::*; - -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd" -))] -pub use self::getres::*; - -feature! { -#![feature = "user"] - -/// User identifier -/// -/// Newtype pattern around `uid_t` (which is just alias). It prevents bugs caused by accidentally -/// passing wrong value. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub struct Uid(uid_t); - -impl Uid { - /// Creates `Uid` from raw `uid_t`. - pub const fn from_raw(uid: uid_t) -> Self { - Uid(uid) - } - - /// Returns Uid of calling process. This is practically a more Rusty alias for `getuid`. - #[doc(alias("getuid"))] - pub fn current() -> Self { - getuid() - } - - /// Returns effective Uid of calling process. This is practically a more Rusty alias for `geteuid`. - #[doc(alias("geteuid"))] - pub fn effective() -> Self { - geteuid() - } - - /// Returns true if the `Uid` represents privileged user - root. (If it equals zero.) - pub const fn is_root(self) -> bool { - self.0 == ROOT.0 - } - - /// Get the raw `uid_t` wrapped by `self`. - pub const fn as_raw(self) -> uid_t { - self.0 - } -} - -impl From<Uid> for uid_t { - fn from(uid: Uid) -> Self { - uid.0 - } -} - -impl From<uid_t> for Uid { - fn from(uid: uid_t) -> Self { - Uid(uid) - } -} - -impl fmt::Display for Uid { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self.0, f) - } -} - -/// Constant for UID = 0 -pub const ROOT: Uid = Uid(0); - -/// Group identifier -/// -/// Newtype pattern around `gid_t` (which is just alias). It prevents bugs caused by accidentally -/// passing wrong value. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub struct Gid(gid_t); - -impl Gid { - /// Creates `Gid` from raw `gid_t`. - pub const fn from_raw(gid: gid_t) -> Self { - Gid(gid) - } - - /// Returns Gid of calling process. This is practically a more Rusty alias for `getgid`. - #[doc(alias("getgid"))] - pub fn current() -> Self { - getgid() - } - - /// Returns effective Gid of calling process. This is practically a more Rusty alias for `getegid`. - #[doc(alias("getegid"))] - pub fn effective() -> Self { - getegid() - } - - /// Get the raw `gid_t` wrapped by `self`. - pub const fn as_raw(self) -> gid_t { - self.0 - } -} - -impl From<Gid> for gid_t { - fn from(gid: Gid) -> Self { - gid.0 - } -} - -impl From<gid_t> for Gid { - fn from(gid: gid_t) -> Self { - Gid(gid) - } -} - -impl fmt::Display for Gid { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self.0, f) - } -} -} - -feature! { -#![feature = "process"] -/// Process identifier -/// -/// Newtype pattern around `pid_t` (which is just alias). It prevents bugs caused by accidentally -/// passing wrong value. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] -pub struct Pid(pid_t); - -impl Pid { - /// Creates `Pid` from raw `pid_t`. - pub const fn from_raw(pid: pid_t) -> Self { - Pid(pid) - } - - /// Returns PID of calling process - #[doc(alias("getpid"))] - pub fn this() -> Self { - getpid() - } - - /// Returns PID of parent of calling process - #[doc(alias("getppid"))] - pub fn parent() -> Self { - getppid() - } - - /// Get the raw `pid_t` wrapped by `self`. - pub const fn as_raw(self) -> pid_t { - self.0 - } -} - -impl From<Pid> for pid_t { - fn from(pid: Pid) -> Self { - pid.0 - } -} - -impl fmt::Display for Pid { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self.0, f) - } -} - - -/// Represents the successful result of calling `fork` -/// -/// When `fork` is called, the process continues execution in the parent process -/// and in the new child. This return type can be examined to determine whether -/// you are now executing in the parent process or in the child. -#[derive(Clone, Copy, Debug)] -pub enum ForkResult { - Parent { child: Pid }, - Child, -} - -impl ForkResult { - - /// Return `true` if this is the child process of the `fork()` - #[inline] - pub fn is_child(self) -> bool { - matches!(self, ForkResult::Child) - } - - /// Returns `true` if this is the parent process of the `fork()` - #[inline] - pub fn is_parent(self) -> bool { - !self.is_child() - } -} - -/// Create a new child process duplicating the parent process ([see -/// fork(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html)). -/// -/// After successfully calling the fork system call, a second process will -/// be created which is identical to the original except for the pid and the -/// return value of this function. As an example: -/// -/// ``` -/// use nix::{sys::wait::waitpid,unistd::{fork, ForkResult, write}}; -/// -/// match unsafe{fork()} { -/// Ok(ForkResult::Parent { child, .. }) => { -/// println!("Continuing execution in parent process, new child has pid: {}", child); -/// waitpid(child, None).unwrap(); -/// } -/// Ok(ForkResult::Child) => { -/// // Unsafe to use `println!` (or `unwrap`) here. See Safety. -/// write(libc::STDOUT_FILENO, "I'm a new child process\n".as_bytes()).ok(); -/// unsafe { libc::_exit(0) }; -/// } -/// Err(_) => println!("Fork failed"), -/// } -/// ``` -/// -/// This will print something like the following (order nondeterministic). The -/// thing to note is that you end up with two processes continuing execution -/// immediately after the fork call but with different match arms. -/// -/// ```text -/// Continuing execution in parent process, new child has pid: 1234 -/// I'm a new child process -/// ``` -/// -/// # Safety -/// -/// In a multithreaded program, only [async-signal-safe] functions like `pause` -/// and `_exit` may be called by the child (the parent isn't restricted). Note -/// that memory allocation may **not** be async-signal-safe and thus must be -/// prevented. -/// -/// Those functions are only a small subset of your operating system's API, so -/// special care must be taken to only invoke code you can control and audit. -/// -/// [async-signal-safe]: https://man7.org/linux/man-pages/man7/signal-safety.7.html -#[inline] -pub unsafe fn fork() -> Result<ForkResult> { - use self::ForkResult::*; - let res = libc::fork(); - - Errno::result(res).map(|res| match res { - 0 => Child, - res => Parent { child: Pid(res) }, - }) -} - -/// Get the pid of this process (see -/// [getpid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpid.html)). -/// -/// Since you are running code, there is always a pid to return, so there -/// is no error case that needs to be handled. -#[inline] -pub fn getpid() -> Pid { - Pid(unsafe { libc::getpid() }) -} - -/// Get the pid of this processes' parent (see -/// [getpid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getppid.html)). -/// -/// There is always a parent pid to return, so there is no error case that needs -/// to be handled. -#[inline] -pub fn getppid() -> Pid { - Pid(unsafe { libc::getppid() }) // no error handling, according to man page: "These functions are always successful." -} - -/// Set a process group ID (see -/// [setpgid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpgid.html)). -/// -/// Set the process group id (PGID) of a particular process. If a pid of zero -/// is specified, then the pid of the calling process is used. Process groups -/// may be used to group together a set of processes in order for the OS to -/// apply some operations across the group. -/// -/// `setsid()` may be used to create a new process group. -#[inline] -pub fn setpgid(pid: Pid, pgid: Pid) -> Result<()> { - let res = unsafe { libc::setpgid(pid.into(), pgid.into()) }; - Errno::result(res).map(drop) -} -#[inline] -pub fn getpgid(pid: Option<Pid>) -> Result<Pid> { - let res = unsafe { libc::getpgid(pid.unwrap_or(Pid(0)).into()) }; - Errno::result(res).map(Pid) -} - -/// Create new session and set process group id (see -/// [setsid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsid.html)). -#[inline] -pub fn setsid() -> Result<Pid> { - Errno::result(unsafe { libc::setsid() }).map(Pid) -} - -/// Get the process group ID of a session leader -/// [getsid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsid.html). -/// -/// Obtain the process group ID of the process that is the session leader of the process specified -/// by pid. If pid is zero, it specifies the calling process. -#[inline] -#[cfg(not(target_os = "redox"))] -pub fn getsid(pid: Option<Pid>) -> Result<Pid> { - let res = unsafe { libc::getsid(pid.unwrap_or(Pid(0)).into()) }; - Errno::result(res).map(Pid) -} -} - -feature! { -#![all(feature = "process", feature = "term")] -/// Get the terminal foreground process group (see -/// [tcgetpgrp(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetpgrp.html)). -/// -/// Get the group process id (GPID) of the foreground process group on the -/// terminal associated to file descriptor (FD). -#[inline] -pub fn tcgetpgrp(fd: c_int) -> Result<Pid> { - let res = unsafe { libc::tcgetpgrp(fd) }; - Errno::result(res).map(Pid) -} -/// Set the terminal foreground process group (see -/// [tcgetpgrp(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetpgrp.html)). -/// -/// Get the group process id (PGID) to the foreground process group on the -/// terminal associated to file descriptor (FD). -#[inline] -pub fn tcsetpgrp(fd: c_int, pgrp: Pid) -> Result<()> { - let res = unsafe { libc::tcsetpgrp(fd, pgrp.into()) }; - Errno::result(res).map(drop) -} -} - -feature! { -#![feature = "process"] -/// Get the group id of the calling process (see -///[getpgrp(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpgrp.html)). -/// -/// Get the process group id (PGID) of the calling process. -/// According to the man page it is always successful. -#[inline] -pub fn getpgrp() -> Pid { - Pid(unsafe { libc::getpgrp() }) -} - -/// Get the caller's thread ID (see -/// [gettid(2)](https://man7.org/linux/man-pages/man2/gettid.2.html). -/// -/// This function is only available on Linux based systems. In a single -/// threaded process, the main thread will have the same ID as the process. In -/// a multithreaded process, each thread will have a unique thread id but the -/// same process ID. -/// -/// No error handling is required as a thread id should always exist for any -/// process, even if threads are not being used. -#[cfg(any(target_os = "linux", target_os = "android"))] -#[inline] -pub fn gettid() -> Pid { - Pid(unsafe { libc::syscall(libc::SYS_gettid) as pid_t }) -} -} - -feature! { -#![feature = "fs"] -/// Create a copy of the specified file descriptor (see -/// [dup(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html)). -/// -/// The new file descriptor will have a new index but refer to the same -/// resource as the old file descriptor and the old and new file descriptors may -/// be used interchangeably. The new and old file descriptor share the same -/// underlying resource, offset, and file status flags. The actual index used -/// for the file descriptor will be the lowest fd index that is available. -/// -/// The two file descriptors do not share file descriptor flags (e.g. `OFlag::FD_CLOEXEC`). -#[inline] -pub fn dup(oldfd: RawFd) -> Result<RawFd> { - let res = unsafe { libc::dup(oldfd) }; - - Errno::result(res) -} - -/// Create a copy of the specified file descriptor using the specified fd (see -/// [dup(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html)). -/// -/// This function behaves similar to `dup()` except that it will try to use the -/// specified fd instead of allocating a new one. See the man pages for more -/// detail on the exact behavior of this function. -#[inline] -pub fn dup2(oldfd: RawFd, newfd: RawFd) -> Result<RawFd> { - let res = unsafe { libc::dup2(oldfd, newfd) }; - - Errno::result(res) -} - -/// Create a new copy of the specified file descriptor using the specified fd -/// and flags (see [dup(2)](https://man7.org/linux/man-pages/man2/dup.2.html)). -/// -/// This function behaves similar to `dup2()` but allows for flags to be -/// specified. -pub fn dup3(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> { - dup3_polyfill(oldfd, newfd, flags) -} - -#[inline] -fn dup3_polyfill(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> { - if oldfd == newfd { - return Err(Errno::EINVAL); - } - - let fd = dup2(oldfd, newfd)?; - - if flags.contains(OFlag::O_CLOEXEC) { - if let Err(e) = fcntl(fd, F_SETFD(FdFlag::FD_CLOEXEC)) { - let _ = close(fd); - return Err(e); - } - } - - Ok(fd) -} - -/// Change the current working directory of the calling process (see -/// [chdir(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/chdir.html)). -/// -/// This function may fail in a number of different scenarios. See the man -/// pages for additional details on possible failure cases. -#[inline] -pub fn chdir<P: ?Sized + NixPath>(path: &P) -> Result<()> { - let res = path.with_nix_path(|cstr| { - unsafe { libc::chdir(cstr.as_ptr()) } - })?; - - Errno::result(res).map(drop) -} - -/// Change the current working directory of the process to the one -/// given as an open file descriptor (see -/// [fchdir(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchdir.html)). -/// -/// This function may fail in a number of different scenarios. See the man -/// pages for additional details on possible failure cases. -#[inline] -#[cfg(not(target_os = "fuchsia"))] -pub fn fchdir(dirfd: RawFd) -> Result<()> { - let res = unsafe { libc::fchdir(dirfd) }; - - Errno::result(res).map(drop) -} - -/// Creates new directory `path` with access rights `mode`. (see [mkdir(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdir.html)) -/// -/// # Errors -/// -/// There are several situations where mkdir might fail: -/// -/// - current user has insufficient rights in the parent directory -/// - the path already exists -/// - the path name is too long (longer than `PATH_MAX`, usually 4096 on linux, 1024 on OS X) -/// -/// # Example -/// -/// ```rust -/// use nix::unistd; -/// use nix::sys::stat; -/// use tempfile::tempdir; -/// -/// let tmp_dir1 = tempdir().unwrap(); -/// let tmp_dir2 = tmp_dir1.path().join("new_dir"); -/// -/// // create new directory and give read, write and execute rights to the owner -/// match unistd::mkdir(&tmp_dir2, stat::Mode::S_IRWXU) { -/// Ok(_) => println!("created {:?}", tmp_dir2), -/// Err(err) => println!("Error creating directory: {}", err), -/// } -/// ``` -#[inline] -pub fn mkdir<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> { - let res = path.with_nix_path(|cstr| { - unsafe { libc::mkdir(cstr.as_ptr(), mode.bits() as mode_t) } - })?; - - Errno::result(res).map(drop) -} - -/// Creates new fifo special file (named pipe) with path `path` and access rights `mode`. -/// -/// # Errors -/// -/// There are several situations where mkfifo might fail: -/// -/// - current user has insufficient rights in the parent directory -/// - the path already exists -/// - the path name is too long (longer than `PATH_MAX`, usually 4096 on linux, 1024 on OS X) -/// -/// For a full list consult -/// [posix specification](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkfifo.html) -/// -/// # Example -/// -/// ```rust -/// use nix::unistd; -/// use nix::sys::stat; -/// use tempfile::tempdir; -/// -/// let tmp_dir = tempdir().unwrap(); -/// let fifo_path = tmp_dir.path().join("foo.pipe"); -/// -/// // create new fifo and give read, write and execute rights to the owner -/// match unistd::mkfifo(&fifo_path, stat::Mode::S_IRWXU) { -/// Ok(_) => println!("created {:?}", fifo_path), -/// Err(err) => println!("Error creating fifo: {}", err), -/// } -/// ``` -#[inline] -#[cfg(not(target_os = "redox"))] // RedoxFS does not support fifo yet -pub fn mkfifo<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> { - let res = path.with_nix_path(|cstr| { - unsafe { libc::mkfifo(cstr.as_ptr(), mode.bits() as mode_t) } - })?; - - Errno::result(res).map(drop) -} - -/// Creates new fifo special file (named pipe) with path `path` and access rights `mode`. -/// -/// If `dirfd` has a value, then `path` is relative to directory associated with the file descriptor. -/// -/// If `dirfd` is `None`, then `path` is relative to the current working directory. -/// -/// # References -/// -/// [mkfifoat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkfifoat.html). -// mkfifoat is not implemented in OSX or android -#[inline] -#[cfg(not(any( - target_os = "macos", target_os = "ios", target_os = "haiku", - target_os = "android", target_os = "redox")))] -pub fn mkfifoat<P: ?Sized + NixPath>(dirfd: Option<RawFd>, path: &P, mode: Mode) -> Result<()> { - let res = path.with_nix_path(|cstr| unsafe { - libc::mkfifoat(at_rawfd(dirfd), cstr.as_ptr(), mode.bits() as mode_t) - })?; - - Errno::result(res).map(drop) -} - -/// Creates a symbolic link at `path2` which points to `path1`. -/// -/// If `dirfd` has a value, then `path2` is relative to directory associated -/// with the file descriptor. -/// -/// If `dirfd` is `None`, then `path2` is relative to the current working -/// directory. This is identical to `libc::symlink(path1, path2)`. -/// -/// See also [symlinkat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/symlinkat.html). -#[cfg(not(target_os = "redox"))] -pub fn symlinkat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>( - path1: &P1, - dirfd: Option<RawFd>, - path2: &P2) -> Result<()> { - let res = - path1.with_nix_path(|path1| { - path2.with_nix_path(|path2| { - unsafe { - libc::symlinkat( - path1.as_ptr(), - dirfd.unwrap_or(libc::AT_FDCWD), - path2.as_ptr() - ) - } - }) - })??; - Errno::result(res).map(drop) -} -} - -// Double the buffer capacity up to limit. In case it already has -// reached the limit, return Errno::ERANGE. -#[cfg(any(feature = "fs", feature = "user"))] -fn reserve_double_buffer_size<T>(buf: &mut Vec<T>, limit: usize) -> Result<()> { - use std::cmp::min; - - if buf.capacity() >= limit { - return Err(Errno::ERANGE); - } - - let capacity = min(buf.capacity() * 2, limit); - buf.reserve(capacity); - - Ok(()) -} - -feature! { -#![feature = "fs"] - -/// Returns the current directory as a `PathBuf` -/// -/// Err is returned if the current user doesn't have the permission to read or search a component -/// of the current path. -/// -/// # Example -/// -/// ```rust -/// use nix::unistd; -/// -/// // assume that we are allowed to get current directory -/// let dir = unistd::getcwd().unwrap(); -/// println!("The current directory is {:?}", dir); -/// ``` -#[inline] -pub fn getcwd() -> Result<PathBuf> { - let mut buf = Vec::with_capacity(512); - loop { - unsafe { - let ptr = buf.as_mut_ptr() as *mut c_char; - - // The buffer must be large enough to store the absolute pathname plus - // a terminating null byte, or else null is returned. - // To safely handle this we start with a reasonable size (512 bytes) - // and double the buffer size upon every error - if !libc::getcwd(ptr, buf.capacity()).is_null() { - let len = CStr::from_ptr(buf.as_ptr() as *const c_char).to_bytes().len(); - buf.set_len(len); - buf.shrink_to_fit(); - return Ok(PathBuf::from(OsString::from_vec(buf))); - } else { - let error = Errno::last(); - // ERANGE means buffer was too small to store directory name - if error != Errno::ERANGE { - return Err(error); - } - } - - // Trigger the internal buffer resizing logic. - reserve_double_buffer_size(&mut buf, PATH_MAX as usize)?; - } - } -} -} - -feature! { -#![all(feature = "user", feature = "fs")] - -/// Computes the raw UID and GID values to pass to a `*chown` call. -// The cast is not unnecessary on all platforms. -#[allow(clippy::unnecessary_cast)] -fn chown_raw_ids(owner: Option<Uid>, group: Option<Gid>) -> (libc::uid_t, libc::gid_t) { - // According to the POSIX specification, -1 is used to indicate that owner and group - // are not to be changed. Since uid_t and gid_t are unsigned types, we have to wrap - // around to get -1. - let uid = owner.map(Into::into) - .unwrap_or_else(|| (0 as uid_t).wrapping_sub(1)); - let gid = group.map(Into::into) - .unwrap_or_else(|| (0 as gid_t).wrapping_sub(1)); - (uid, gid) -} - -/// Change the ownership of the file at `path` to be owned by the specified -/// `owner` (user) and `group` (see -/// [chown(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/chown.html)). -/// -/// The owner/group for the provided path name will not be modified if `None` is -/// provided for that argument. Ownership change will be attempted for the path -/// only if `Some` owner/group is provided. -#[inline] -pub fn chown<P: ?Sized + NixPath>(path: &P, owner: Option<Uid>, group: Option<Gid>) -> Result<()> { - let res = path.with_nix_path(|cstr| { - let (uid, gid) = chown_raw_ids(owner, group); - unsafe { libc::chown(cstr.as_ptr(), uid, gid) } - })?; - - Errno::result(res).map(drop) -} - -/// Change the ownership of the file referred to by the open file descriptor `fd` to be owned by -/// the specified `owner` (user) and `group` (see -/// [fchown(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchown.html)). -/// -/// The owner/group for the provided file will not be modified if `None` is -/// provided for that argument. Ownership change will be attempted for the path -/// only if `Some` owner/group is provided. -#[inline] -pub fn fchown(fd: RawFd, owner: Option<Uid>, group: Option<Gid>) -> Result<()> { - let (uid, gid) = chown_raw_ids(owner, group); - let res = unsafe { libc::fchown(fd, uid, gid) }; - Errno::result(res).map(drop) -} - -/// Flags for `fchownat` function. -#[derive(Clone, Copy, Debug)] -pub enum FchownatFlags { - FollowSymlink, - NoFollowSymlink, -} - -/// Change the ownership of the file at `path` to be owned by the specified -/// `owner` (user) and `group`. -/// -/// The owner/group for the provided path name will not be modified if `None` is -/// provided for that argument. Ownership change will be attempted for the path -/// only if `Some` owner/group is provided. -/// -/// The file to be changed is determined relative to the directory associated -/// with the file descriptor `dirfd` or the current working directory -/// if `dirfd` is `None`. -/// -/// If `flag` is `FchownatFlags::NoFollowSymlink` and `path` names a symbolic link, -/// then the mode of the symbolic link is changed. -/// -/// `fchownat(None, path, owner, group, FchownatFlags::NoFollowSymlink)` is identical to -/// a call `libc::lchown(path, owner, group)`. That's why `lchown` is unimplemented in -/// the `nix` crate. -/// -/// # References -/// -/// [fchownat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchownat.html). -#[cfg(not(target_os = "redox"))] -pub fn fchownat<P: ?Sized + NixPath>( - dirfd: Option<RawFd>, - path: &P, - owner: Option<Uid>, - group: Option<Gid>, - flag: FchownatFlags, -) -> Result<()> { - let atflag = - match flag { - FchownatFlags::FollowSymlink => AtFlags::empty(), - FchownatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW, - }; - let res = path.with_nix_path(|cstr| unsafe { - let (uid, gid) = chown_raw_ids(owner, group); - libc::fchownat(at_rawfd(dirfd), cstr.as_ptr(), uid, gid, - atflag.bits() as libc::c_int) - })?; - - Errno::result(res).map(drop) -} -} - -feature! { -#![feature = "process"] -fn to_exec_array<S: AsRef<CStr>>(args: &[S]) -> Vec<*const c_char> { - use std::iter::once; - args.iter() - .map(|s| s.as_ref().as_ptr()) - .chain(once(ptr::null())) - .collect() -} - -/// Replace the current process image with a new one (see -/// [exec(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)). -/// -/// See the `::nix::unistd::execve` system call for additional details. `execv` -/// performs the same action but does not allow for customization of the -/// environment for the new process. -#[inline] -pub fn execv<S: AsRef<CStr>>(path: &CStr, argv: &[S]) -> Result<Infallible> { - let args_p = to_exec_array(argv); - - unsafe { - libc::execv(path.as_ptr(), args_p.as_ptr()) - }; - - Err(Errno::last()) -} - - -/// Replace the current process image with a new one (see -/// [execve(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)). -/// -/// The execve system call allows for another process to be "called" which will -/// replace the current process image. That is, this process becomes the new -/// command that is run. On success, this function will not return. Instead, -/// the new program will run until it exits. -/// -/// `::nix::unistd::execv` and `::nix::unistd::execve` take as arguments a slice -/// of `::std::ffi::CString`s for `args` and `env` (for `execve`). Each element -/// in the `args` list is an argument to the new process. Each element in the -/// `env` list should be a string in the form "key=value". -#[inline] -pub fn execve<SA: AsRef<CStr>, SE: AsRef<CStr>>(path: &CStr, args: &[SA], env: &[SE]) -> Result<Infallible> { - let args_p = to_exec_array(args); - let env_p = to_exec_array(env); - - unsafe { - libc::execve(path.as_ptr(), args_p.as_ptr(), env_p.as_ptr()) - }; - - Err(Errno::last()) -} - -/// Replace the current process image with a new one and replicate shell `PATH` -/// searching behavior (see -/// [exec(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)). -/// -/// See `::nix::unistd::execve` for additional details. `execvp` behaves the -/// same as execv except that it will examine the `PATH` environment variables -/// for file names not specified with a leading slash. For example, `execv` -/// would not work if "bash" was specified for the path argument, but `execvp` -/// would assuming that a bash executable was on the system `PATH`. -#[inline] -pub fn execvp<S: AsRef<CStr>>(filename: &CStr, args: &[S]) -> Result<Infallible> { - let args_p = to_exec_array(args); - - unsafe { - libc::execvp(filename.as_ptr(), args_p.as_ptr()) - }; - - Err(Errno::last()) -} - -/// Replace the current process image with a new one and replicate shell `PATH` -/// searching behavior (see -/// [`execvpe(3)`](https://man7.org/linux/man-pages/man3/exec.3.html)). -/// -/// This functions like a combination of `execvp(2)` and `execve(2)` to pass an -/// environment and have a search path. See these two for additional -/// information. -#[cfg(any(target_os = "haiku", - target_os = "linux", - target_os = "openbsd"))] -pub fn execvpe<SA: AsRef<CStr>, SE: AsRef<CStr>>(filename: &CStr, args: &[SA], env: &[SE]) -> Result<Infallible> { - let args_p = to_exec_array(args); - let env_p = to_exec_array(env); - - unsafe { - libc::execvpe(filename.as_ptr(), args_p.as_ptr(), env_p.as_ptr()) - }; - - Err(Errno::last()) -} - -/// Replace the current process image with a new one (see -/// [fexecve(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fexecve.html)). -/// -/// The `fexecve` function allows for another process to be "called" which will -/// replace the current process image. That is, this process becomes the new -/// command that is run. On success, this function will not return. Instead, -/// the new program will run until it exits. -/// -/// This function is similar to `execve`, except that the program to be executed -/// is referenced as a file descriptor instead of a path. -#[cfg(any(target_os = "android", - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd"))] -#[inline] -pub fn fexecve<SA: AsRef<CStr> ,SE: AsRef<CStr>>(fd: RawFd, args: &[SA], env: &[SE]) -> Result<Infallible> { - let args_p = to_exec_array(args); - let env_p = to_exec_array(env); - - unsafe { - libc::fexecve(fd, args_p.as_ptr(), env_p.as_ptr()) - }; - - Err(Errno::last()) -} - -/// Execute program relative to a directory file descriptor (see -/// [execveat(2)](https://man7.org/linux/man-pages/man2/execveat.2.html)). -/// -/// The `execveat` function allows for another process to be "called" which will -/// replace the current process image. That is, this process becomes the new -/// command that is run. On success, this function will not return. Instead, -/// the new program will run until it exits. -/// -/// This function is similar to `execve`, except that the program to be executed -/// is referenced as a file descriptor to the base directory plus a path. -#[cfg(any(target_os = "android", target_os = "linux"))] -#[inline] -pub fn execveat<SA: AsRef<CStr>,SE: AsRef<CStr>>(dirfd: RawFd, pathname: &CStr, args: &[SA], - env: &[SE], flags: super::fcntl::AtFlags) -> Result<Infallible> { - let args_p = to_exec_array(args); - let env_p = to_exec_array(env); - - unsafe { - libc::syscall(libc::SYS_execveat, dirfd, pathname.as_ptr(), - args_p.as_ptr(), env_p.as_ptr(), flags); - }; - - Err(Errno::last()) -} - -/// Daemonize this process by detaching from the controlling terminal (see -/// [daemon(3)](https://man7.org/linux/man-pages/man3/daemon.3.html)). -/// -/// When a process is launched it is typically associated with a parent and it, -/// in turn, by its controlling terminal/process. In order for a process to run -/// in the "background" it must daemonize itself by detaching itself. Under -/// posix, this is done by doing the following: -/// -/// 1. Parent process (this one) forks -/// 2. Parent process exits -/// 3. Child process continues to run. -/// -/// `nochdir`: -/// -/// * `nochdir = true`: The current working directory after daemonizing will -/// be the current working directory. -/// * `nochdir = false`: The current working directory after daemonizing will -/// be the root direcory, `/`. -/// -/// `noclose`: -/// -/// * `noclose = true`: The process' current stdin, stdout, and stderr file -/// descriptors will remain identical after daemonizing. -/// * `noclose = false`: The process' stdin, stdout, and stderr will point to -/// `/dev/null` after daemonizing. -#[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris"))] -pub fn daemon(nochdir: bool, noclose: bool) -> Result<()> { - let res = unsafe { libc::daemon(nochdir as c_int, noclose as c_int) }; - Errno::result(res).map(drop) -} -} - -feature! { -#![feature = "hostname"] - -/// Set the system host name (see -/// [sethostname(2)](https://man7.org/linux/man-pages/man2/gethostname.2.html)). -/// -/// Given a name, attempt to update the system host name to the given string. -/// On some systems, the host name is limited to as few as 64 bytes. An error -/// will be returned if the name is not valid or the current process does not -/// have permissions to update the host name. -#[cfg(not(target_os = "redox"))] -pub fn sethostname<S: AsRef<OsStr>>(name: S) -> Result<()> { - // Handle some differences in type of the len arg across platforms. - cfg_if! { - if #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", - target_os = "macos", - target_os = "solaris", ))] { - type sethostname_len_t = c_int; - } else { - type sethostname_len_t = size_t; - } - } - let ptr = name.as_ref().as_bytes().as_ptr() as *const c_char; - let len = name.as_ref().len() as sethostname_len_t; - - let res = unsafe { libc::sethostname(ptr, len) }; - Errno::result(res).map(drop) -} - -/// Get the host name and store it in an internally allocated buffer, returning an -/// `OsString` on success (see -/// [gethostname(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/gethostname.html)). -/// -/// This function call attempts to get the host name for the running system and -/// store it in an internal buffer, returning it as an `OsString` if successful. -/// -/// ```no_run -/// use nix::unistd; -/// -/// let hostname = unistd::gethostname().expect("Failed getting hostname"); -/// let hostname = hostname.into_string().expect("Hostname wasn't valid UTF-8"); -/// println!("Hostname: {}", hostname); -/// ``` -pub fn gethostname() -> Result<OsString> { - // The capacity is the max length of a hostname plus the NUL terminator. - let mut buffer: Vec<u8> = Vec::with_capacity(256); - let ptr = buffer.as_mut_ptr() as *mut c_char; - let len = buffer.capacity() as size_t; - - let res = unsafe { libc::gethostname(ptr, len) }; - Errno::result(res).map(|_| { - unsafe { - buffer.as_mut_ptr().wrapping_add(len - 1).write(0); // ensure always null-terminated - let len = CStr::from_ptr(buffer.as_ptr() as *const c_char).len(); - buffer.set_len(len); - } - OsString::from_vec(buffer) - }) -} -} - -/// Close a raw file descriptor -/// -/// Be aware that many Rust types implicitly close-on-drop, including -/// `std::fs::File`. Explicitly closing them with this method too can result in -/// a double-close condition, which can cause confusing `EBADF` errors in -/// seemingly unrelated code. Caveat programmer. See also -/// [close(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html). -/// -/// # Examples -/// -/// ```no_run -/// use std::os::unix::io::AsRawFd; -/// use nix::unistd::close; -/// -/// let f = tempfile::tempfile().unwrap(); -/// close(f.as_raw_fd()).unwrap(); // Bad! f will also close on drop! -/// ``` -/// -/// ```rust -/// use std::os::unix::io::IntoRawFd; -/// use nix::unistd::close; -/// -/// let f = tempfile::tempfile().unwrap(); -/// close(f.into_raw_fd()).unwrap(); // Good. into_raw_fd consumes f -/// ``` -pub fn close(fd: RawFd) -> Result<()> { - let res = unsafe { libc::close(fd) }; - Errno::result(res).map(drop) -} - -/// Read from a raw file descriptor. -/// -/// See also [read(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html) -pub fn read(fd: RawFd, buf: &mut [u8]) -> Result<usize> { - let res = unsafe { - libc::read(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t) - }; - - Errno::result(res).map(|r| r as usize) -} - -/// Write to a raw file descriptor. -/// -/// See also [write(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html) -pub fn write(fd: RawFd, buf: &[u8]) -> Result<usize> { - let res = unsafe { - libc::write(fd, buf.as_ptr() as *const c_void, buf.len() as size_t) - }; - - Errno::result(res).map(|r| r as usize) -} - -feature! { -#![feature = "fs"] - -/// Directive that tells [`lseek`] and [`lseek64`] what the offset is relative to. -/// -/// [`lseek`]: ./fn.lseek.html -/// [`lseek64`]: ./fn.lseek64.html -#[repr(i32)] -#[derive(Clone, Copy, Debug)] -pub enum Whence { - /// Specify an offset relative to the start of the file. - SeekSet = libc::SEEK_SET, - /// Specify an offset relative to the current file location. - SeekCur = libc::SEEK_CUR, - /// Specify an offset relative to the end of the file. - SeekEnd = libc::SEEK_END, - /// Specify an offset relative to the next location in the file greater than or - /// equal to offset that contains some data. If offset points to - /// some data, then the file offset is set to offset. - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "solaris"))] - SeekData = libc::SEEK_DATA, - /// Specify an offset relative to the next hole in the file greater than - /// or equal to offset. If offset points into the middle of a hole, then - /// the file offset should be set to offset. If there is no hole past offset, - /// then the file offset should be adjusted to the end of the file (i.e., there - /// is an implicit hole at the end of any file). - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "solaris"))] - SeekHole = libc::SEEK_HOLE -} - -/// Move the read/write file offset. -/// -/// See also [lseek(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/lseek.html) -pub fn lseek(fd: RawFd, offset: off_t, whence: Whence) -> Result<off_t> { - let res = unsafe { libc::lseek(fd, offset, whence as i32) }; - - Errno::result(res).map(|r| r as off_t) -} - -#[cfg(any(target_os = "linux", target_os = "android"))] -pub fn lseek64(fd: RawFd, offset: libc::off64_t, whence: Whence) -> Result<libc::off64_t> { - let res = unsafe { libc::lseek64(fd, offset, whence as i32) }; - - Errno::result(res).map(|r| r as libc::off64_t) -} -} - -/// Create an interprocess channel. -/// -/// See also [pipe(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pipe.html) -pub fn pipe() -> std::result::Result<(RawFd, RawFd), Error> { - let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit(); - - let res = unsafe { libc::pipe(fds.as_mut_ptr() as *mut c_int) }; - - Error::result(res)?; - - unsafe { Ok((fds.assume_init()[0], fds.assume_init()[1])) } -} - -feature! { -#![feature = "fs"] -/// Like `pipe`, but allows setting certain file descriptor flags. -/// -/// The following flags are supported, and will be set atomically as the pipe is -/// created: -/// -/// - `O_CLOEXEC`: Set the close-on-exec flag for the new file descriptors. -#[cfg_attr(target_os = "linux", doc = "- `O_DIRECT`: Create a pipe that performs I/O in \"packet\" mode.")] -#[cfg_attr(target_os = "netbsd", doc = "- `O_NOSIGPIPE`: Return `EPIPE` instead of raising `SIGPIPE`.")] -/// - `O_NONBLOCK`: Set the non-blocking flag for the ends of the pipe. -/// -/// See also [pipe(2)](https://man7.org/linux/man-pages/man2/pipe.2.html) -#[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "redox", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris"))] -pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> { - let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit(); - - let res = unsafe { - libc::pipe2(fds.as_mut_ptr() as *mut c_int, flags.bits()) - }; - - Errno::result(res)?; - - unsafe { Ok((fds.assume_init()[0], fds.assume_init()[1])) } -} - -/// Truncate a file to a specified length -/// -/// See also -/// [truncate(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/truncate.html) -#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] -pub fn truncate<P: ?Sized + NixPath>(path: &P, len: off_t) -> Result<()> { - let res = path.with_nix_path(|cstr| { - unsafe { - libc::truncate(cstr.as_ptr(), len) - } - })?; - - Errno::result(res).map(drop) -} - -/// Truncate a file to a specified length -/// -/// See also -/// [ftruncate(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html) -pub fn ftruncate(fd: RawFd, len: off_t) -> Result<()> { - Errno::result(unsafe { libc::ftruncate(fd, len) }).map(drop) -} - -pub fn isatty(fd: RawFd) -> Result<bool> { - unsafe { - // ENOTTY means `fd` is a valid file descriptor, but not a TTY, so - // we return `Ok(false)` - if libc::isatty(fd) == 1 { - Ok(true) - } else { - match Errno::last() { - Errno::ENOTTY => Ok(false), - err => Err(err), - } - } - } -} - -/// Flags for `linkat` function. -#[derive(Clone, Copy, Debug)] -pub enum LinkatFlags { - SymlinkFollow, - NoSymlinkFollow, -} - -/// Link one file to another file -/// -/// Creates a new link (directory entry) at `newpath` for the existing file at `oldpath`. In the -/// case of a relative `oldpath`, the path is interpreted relative to the directory associated -/// with file descriptor `olddirfd` instead of the current working directory and similiarly for -/// `newpath` and file descriptor `newdirfd`. In case `flag` is LinkatFlags::SymlinkFollow and -/// `oldpath` names a symoblic link, a new link for the target of the symbolic link is created. -/// If either `olddirfd` or `newdirfd` is `None`, `AT_FDCWD` is used respectively where `oldpath` -/// and/or `newpath` is then interpreted relative to the current working directory of the calling -/// process. If either `oldpath` or `newpath` is absolute, then `dirfd` is ignored. -/// -/// # References -/// See also [linkat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/linkat.html) -#[cfg(not(target_os = "redox"))] // RedoxFS does not support symlinks yet -pub fn linkat<P: ?Sized + NixPath>( - olddirfd: Option<RawFd>, - oldpath: &P, - newdirfd: Option<RawFd>, - newpath: &P, - flag: LinkatFlags, -) -> Result<()> { - - let atflag = - match flag { - LinkatFlags::SymlinkFollow => AtFlags::AT_SYMLINK_FOLLOW, - LinkatFlags::NoSymlinkFollow => AtFlags::empty(), - }; - - let res = - oldpath.with_nix_path(|oldcstr| { - newpath.with_nix_path(|newcstr| { - unsafe { - libc::linkat( - at_rawfd(olddirfd), - oldcstr.as_ptr(), - at_rawfd(newdirfd), - newcstr.as_ptr(), - atflag.bits() as libc::c_int - ) - } - }) - })??; - Errno::result(res).map(drop) -} - - -/// Remove a directory entry -/// -/// See also [unlink(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlink.html) -pub fn unlink<P: ?Sized + NixPath>(path: &P) -> Result<()> { - let res = path.with_nix_path(|cstr| { - unsafe { - libc::unlink(cstr.as_ptr()) - } - })?; - Errno::result(res).map(drop) -} - -/// Flags for `unlinkat` function. -#[derive(Clone, Copy, Debug)] -pub enum UnlinkatFlags { - RemoveDir, - NoRemoveDir, -} - -/// Remove a directory entry -/// -/// In the case of a relative path, the directory entry to be removed is determined relative to -/// the directory associated with the file descriptor `dirfd` or the current working directory -/// if `dirfd` is `None`. In the case of an absolute `path` `dirfd` is ignored. If `flag` is -/// `UnlinkatFlags::RemoveDir` then removal of the directory entry specified by `dirfd` and `path` -/// is performed. -/// -/// # References -/// See also [unlinkat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlinkat.html) -#[cfg(not(target_os = "redox"))] -pub fn unlinkat<P: ?Sized + NixPath>( - dirfd: Option<RawFd>, - path: &P, - flag: UnlinkatFlags, -) -> Result<()> { - let atflag = - match flag { - UnlinkatFlags::RemoveDir => AtFlags::AT_REMOVEDIR, - UnlinkatFlags::NoRemoveDir => AtFlags::empty(), - }; - let res = path.with_nix_path(|cstr| { - unsafe { - libc::unlinkat(at_rawfd(dirfd), cstr.as_ptr(), atflag.bits() as libc::c_int) - } - })?; - Errno::result(res).map(drop) -} - - -#[inline] -#[cfg(not(target_os = "fuchsia"))] -pub fn chroot<P: ?Sized + NixPath>(path: &P) -> Result<()> { - let res = path.with_nix_path(|cstr| { - unsafe { libc::chroot(cstr.as_ptr()) } - })?; - - Errno::result(res).map(drop) -} - -/// Commit filesystem caches to disk -/// -/// See also [sync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sync.html) -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd" -))] -pub fn sync() { - unsafe { libc::sync() }; -} - -/// Commit filesystem caches containing file referred to by the open file -/// descriptor `fd` to disk -/// -/// See also [syncfs(2)](https://man7.org/linux/man-pages/man2/sync.2.html) -#[cfg(target_os = "linux")] -pub fn syncfs(fd: RawFd) -> Result<()> { - let res = unsafe { libc::syncfs(fd) }; - - Errno::result(res).map(drop) -} - -/// Synchronize changes to a file -/// -/// See also [fsync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html) -#[inline] -pub fn fsync(fd: RawFd) -> Result<()> { - let res = unsafe { libc::fsync(fd) }; - - Errno::result(res).map(drop) -} - -/// Synchronize the data of a file -/// -/// See also -/// [fdatasync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html) -#[cfg(any(target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "netbsd", - target_os = "openbsd", - target_os = "illumos", - target_os = "solaris"))] -#[inline] -pub fn fdatasync(fd: RawFd) -> Result<()> { - let res = unsafe { libc::fdatasync(fd) }; - - Errno::result(res).map(drop) -} -} - -feature! { -#![feature = "user"] - -/// Get a real user ID -/// -/// See also [getuid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getuid.html) -// POSIX requires that getuid is always successful, so no need to check return -// value or errno. -#[inline] -pub fn getuid() -> Uid { - Uid(unsafe { libc::getuid() }) -} - -/// Get the effective user ID -/// -/// See also [geteuid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/geteuid.html) -// POSIX requires that geteuid is always successful, so no need to check return -// value or errno. -#[inline] -pub fn geteuid() -> Uid { - Uid(unsafe { libc::geteuid() }) -} - -/// Get the real group ID -/// -/// See also [getgid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getgid.html) -// POSIX requires that getgid is always successful, so no need to check return -// value or errno. -#[inline] -pub fn getgid() -> Gid { - Gid(unsafe { libc::getgid() }) -} - -/// Get the effective group ID -/// -/// See also [getegid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getegid.html) -// POSIX requires that getegid is always successful, so no need to check return -// value or errno. -#[inline] -pub fn getegid() -> Gid { - Gid(unsafe { libc::getegid() }) -} - -/// Set the effective user ID -/// -/// See also [seteuid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/seteuid.html) -#[inline] -pub fn seteuid(euid: Uid) -> Result<()> { - let res = unsafe { libc::seteuid(euid.into()) }; - - Errno::result(res).map(drop) -} - -/// Set the effective group ID -/// -/// See also [setegid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setegid.html) -#[inline] -pub fn setegid(egid: Gid) -> Result<()> { - let res = unsafe { libc::setegid(egid.into()) }; - - Errno::result(res).map(drop) -} - -/// Set the user ID -/// -/// See also [setuid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setuid.html) -#[inline] -pub fn setuid(uid: Uid) -> Result<()> { - let res = unsafe { libc::setuid(uid.into()) }; - - Errno::result(res).map(drop) -} - -/// Set the group ID -/// -/// See also [setgid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setgid.html) -#[inline] -pub fn setgid(gid: Gid) -> Result<()> { - let res = unsafe { libc::setgid(gid.into()) }; - - Errno::result(res).map(drop) -} -} - -feature! { -#![all(feature = "fs", feature = "user")] -/// Set the user identity used for filesystem checks per-thread. -/// On both success and failure, this call returns the previous filesystem user -/// ID of the caller. -/// -/// See also [setfsuid(2)](https://man7.org/linux/man-pages/man2/setfsuid.2.html) -#[cfg(any(target_os = "linux", target_os = "android"))] -pub fn setfsuid(uid: Uid) -> Uid { - let prev_fsuid = unsafe { libc::setfsuid(uid.into()) }; - Uid::from_raw(prev_fsuid as uid_t) -} - -/// Set the group identity used for filesystem checks per-thread. -/// On both success and failure, this call returns the previous filesystem group -/// ID of the caller. -/// -/// See also [setfsgid(2)](https://man7.org/linux/man-pages/man2/setfsgid.2.html) -#[cfg(any(target_os = "linux", target_os = "android"))] -pub fn setfsgid(gid: Gid) -> Gid { - let prev_fsgid = unsafe { libc::setfsgid(gid.into()) }; - Gid::from_raw(prev_fsgid as gid_t) -} -} - -feature! { -#![feature = "user"] - -/// Get the list of supplementary group IDs of the calling process. -/// -/// [Further reading](https://pubs.opengroup.org/onlinepubs/009695399/functions/getgroups.html) -/// -/// **Note:** This function is not available for Apple platforms. On those -/// platforms, checking group membership should be achieved via communication -/// with the `opendirectoryd` service. -#[cfg(not(any(target_os = "ios", target_os = "macos")))] -pub fn getgroups() -> Result<Vec<Gid>> { - // First get the maximum number of groups. The value returned - // shall always be greater than or equal to one and less than or - // equal to the value of {NGROUPS_MAX} + 1. - let ngroups_max = match sysconf(SysconfVar::NGROUPS_MAX) { - Ok(Some(n)) => (n + 1) as usize, - Ok(None) | Err(_) => <usize>::max_value(), - }; - - // Next, get the number of groups so we can size our Vec - let ngroups = unsafe { libc::getgroups(0, ptr::null_mut()) }; - - // If there are no supplementary groups, return early. - // This prevents a potential buffer over-read if the number of groups - // increases from zero before the next call. It would return the total - // number of groups beyond the capacity of the buffer. - if ngroups == 0 { - return Ok(Vec::new()); - } - - // Now actually get the groups. We try multiple times in case the number of - // groups has changed since the first call to getgroups() and the buffer is - // now too small. - let mut groups = Vec::<Gid>::with_capacity(Errno::result(ngroups)? as usize); - loop { - // FIXME: On the platforms we currently support, the `Gid` struct has - // the same representation in memory as a bare `gid_t`. This is not - // necessarily the case on all Rust platforms, though. See RFC 1785. - let ngroups = unsafe { - libc::getgroups(groups.capacity() as c_int, groups.as_mut_ptr() as *mut gid_t) - }; - - match Errno::result(ngroups) { - Ok(s) => { - unsafe { groups.set_len(s as usize) }; - return Ok(groups); - }, - Err(Errno::EINVAL) => { - // EINVAL indicates that the buffer size was too - // small, resize it up to ngroups_max as limit. - reserve_double_buffer_size(&mut groups, ngroups_max) - .or(Err(Errno::EINVAL))?; - }, - Err(e) => return Err(e) - } - } -} - -/// Set the list of supplementary group IDs for the calling process. -/// -/// [Further reading](https://man7.org/linux/man-pages/man2/getgroups.2.html) -/// -/// **Note:** This function is not available for Apple platforms. On those -/// platforms, group membership management should be achieved via communication -/// with the `opendirectoryd` service. -/// -/// # Examples -/// -/// `setgroups` can be used when dropping privileges from the root user to a -/// specific user and group. For example, given the user `www-data` with UID -/// `33` and the group `backup` with the GID `34`, one could switch the user as -/// follows: -/// -/// ```rust,no_run -/// # use std::error::Error; -/// # use nix::unistd::*; -/// # -/// # fn try_main() -> Result<(), Box<dyn Error>> { -/// let uid = Uid::from_raw(33); -/// let gid = Gid::from_raw(34); -/// setgroups(&[gid])?; -/// setgid(gid)?; -/// setuid(uid)?; -/// # -/// # Ok(()) -/// # } -/// # -/// # try_main().unwrap(); -/// ``` -#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox", target_os = "haiku")))] -pub fn setgroups(groups: &[Gid]) -> Result<()> { - cfg_if! { - if #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "illumos", - target_os = "openbsd"))] { - type setgroups_ngroups_t = c_int; - } else { - type setgroups_ngroups_t = size_t; - } - } - // FIXME: On the platforms we currently support, the `Gid` struct has the - // same representation in memory as a bare `gid_t`. This is not necessarily - // the case on all Rust platforms, though. See RFC 1785. - let res = unsafe { - libc::setgroups(groups.len() as setgroups_ngroups_t, groups.as_ptr() as *const gid_t) - }; - - Errno::result(res).map(drop) -} - -/// Calculate the supplementary group access list. -/// -/// Gets the group IDs of all groups that `user` is a member of. The additional -/// group `group` is also added to the list. -/// -/// [Further reading](https://man7.org/linux/man-pages/man3/getgrouplist.3.html) -/// -/// **Note:** This function is not available for Apple platforms. On those -/// platforms, checking group membership should be achieved via communication -/// with the `opendirectoryd` service. -/// -/// # Errors -/// -/// Although the `getgrouplist()` call does not return any specific -/// errors on any known platforms, this implementation will return a system -/// error of `EINVAL` if the number of groups to be fetched exceeds the -/// `NGROUPS_MAX` sysconf value. This mimics the behaviour of `getgroups()` -/// and `setgroups()`. Additionally, while some implementations will return a -/// partial list of groups when `NGROUPS_MAX` is exceeded, this implementation -/// will only ever return the complete list or else an error. -#[cfg(not(any(target_os = "illumos", - target_os = "ios", - target_os = "macos", - target_os = "redox")))] -pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> { - let ngroups_max = match sysconf(SysconfVar::NGROUPS_MAX) { - Ok(Some(n)) => n as c_int, - Ok(None) | Err(_) => <c_int>::max_value(), - }; - use std::cmp::min; - let mut groups = Vec::<Gid>::with_capacity(min(ngroups_max, 8) as usize); - cfg_if! { - if #[cfg(any(target_os = "ios", target_os = "macos"))] { - type getgrouplist_group_t = c_int; - } else { - type getgrouplist_group_t = gid_t; - } - } - let gid: gid_t = group.into(); - loop { - let mut ngroups = groups.capacity() as i32; - let ret = unsafe { - libc::getgrouplist(user.as_ptr(), - gid as getgrouplist_group_t, - groups.as_mut_ptr() as *mut getgrouplist_group_t, - &mut ngroups) - }; - - // BSD systems only return 0 or -1, Linux returns ngroups on success. - if ret >= 0 { - unsafe { groups.set_len(ngroups as usize) }; - return Ok(groups); - } else if ret == -1 { - // Returns -1 if ngroups is too small, but does not set errno. - // BSD systems will still fill the groups buffer with as many - // groups as possible, but Linux manpages do not mention this - // behavior. - reserve_double_buffer_size(&mut groups, ngroups_max as usize) - .map_err(|_| Errno::EINVAL)?; - } - } -} - -/// Initialize the supplementary group access list. -/// -/// Sets the supplementary group IDs for the calling process using all groups -/// that `user` is a member of. The additional group `group` is also added to -/// the list. -/// -/// [Further reading](https://man7.org/linux/man-pages/man3/initgroups.3.html) -/// -/// **Note:** This function is not available for Apple platforms. On those -/// platforms, group membership management should be achieved via communication -/// with the `opendirectoryd` service. -/// -/// # Examples -/// -/// `initgroups` can be used when dropping privileges from the root user to -/// another user. For example, given the user `www-data`, we could look up the -/// UID and GID for the user in the system's password database (usually found -/// in `/etc/passwd`). If the `www-data` user's UID and GID were `33` and `33`, -/// respectively, one could switch the user as follows: -/// -/// ```rust,no_run -/// # use std::error::Error; -/// # use std::ffi::CString; -/// # use nix::unistd::*; -/// # -/// # fn try_main() -> Result<(), Box<dyn Error>> { -/// let user = CString::new("www-data").unwrap(); -/// let uid = Uid::from_raw(33); -/// let gid = Gid::from_raw(33); -/// initgroups(&user, gid)?; -/// setgid(gid)?; -/// setuid(uid)?; -/// # -/// # Ok(()) -/// # } -/// # -/// # try_main().unwrap(); -/// ``` -#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox", target_os = "haiku")))] -pub fn initgroups(user: &CStr, group: Gid) -> Result<()> { - cfg_if! { - if #[cfg(any(target_os = "ios", target_os = "macos"))] { - type initgroups_group_t = c_int; - } else { - type initgroups_group_t = gid_t; - } - } - let gid: gid_t = group.into(); - let res = unsafe { libc::initgroups(user.as_ptr(), gid as initgroups_group_t) }; - - Errno::result(res).map(drop) -} -} - -feature! { -#![feature = "signal"] - -/// Suspend the thread until a signal is received. -/// -/// See also [pause(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pause.html). -#[inline] -#[cfg(not(target_os = "redox"))] -pub fn pause() { - unsafe { libc::pause() }; -} - -pub mod alarm { - //! Alarm signal scheduling. - //! - //! Scheduling an alarm will trigger a `SIGALRM` signal when the time has - //! elapsed, which has to be caught, because the default action for the - //! signal is to terminate the program. This signal also can't be ignored - //! because the system calls like `pause` will not be interrupted, see the - //! second example below. - //! - //! # Examples - //! - //! Canceling an alarm: - //! - //! ``` - //! use nix::unistd::alarm; - //! - //! // Set an alarm for 60 seconds from now. - //! alarm::set(60); - //! - //! // Cancel the above set alarm, which returns the number of seconds left - //! // of the previously set alarm. - //! assert_eq!(alarm::cancel(), Some(60)); - //! ``` - //! - //! Scheduling an alarm and waiting for the signal: - //! -#![cfg_attr(target_os = "redox", doc = " ```rust,ignore")] -#![cfg_attr(not(target_os = "redox"), doc = " ```rust")] - //! use std::time::{Duration, Instant}; - //! - //! use nix::unistd::{alarm, pause}; - //! use nix::sys::signal::*; - //! - //! // We need to setup an empty signal handler to catch the alarm signal, - //! // otherwise the program will be terminated once the signal is delivered. - //! extern fn signal_handler(_: nix::libc::c_int) { } - //! let sa = SigAction::new( - //! SigHandler::Handler(signal_handler), - //! SaFlags::SA_RESTART, - //! SigSet::empty() - //! ); - //! unsafe { - //! sigaction(Signal::SIGALRM, &sa); - //! } - //! - //! let start = Instant::now(); - //! - //! // Set an alarm for 1 second from now. - //! alarm::set(1); - //! - //! // Pause the process until the alarm signal is received. - //! let mut sigset = SigSet::empty(); - //! sigset.add(Signal::SIGALRM); - //! sigset.wait(); - //! - //! assert!(start.elapsed() >= Duration::from_secs(1)); - //! ``` - //! - //! # References - //! - //! See also [alarm(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/alarm.html). - - /// Schedule an alarm signal. - /// - /// This will cause the system to generate a `SIGALRM` signal for the - /// process after the specified number of seconds have elapsed. - /// - /// Returns the leftover time of a previously set alarm if there was one. - pub fn set(secs: libc::c_uint) -> Option<libc::c_uint> { - assert!(secs != 0, "passing 0 to `alarm::set` is not allowed, to cancel an alarm use `alarm::cancel`"); - alarm(secs) - } - - /// Cancel an previously set alarm signal. - /// - /// Returns the leftover time of a previously set alarm if there was one. - pub fn cancel() -> Option<libc::c_uint> { - alarm(0) - } - - fn alarm(secs: libc::c_uint) -> Option<libc::c_uint> { - match unsafe { libc::alarm(secs) } { - 0 => None, - secs => Some(secs), - } - } -} -} - -/// Suspend execution for an interval of time -/// -/// See also [sleep(2)](https://pubs.opengroup.org/onlinepubs/009695399/functions/sleep.html#tag_03_705_05) -// Per POSIX, does not fail -#[inline] -pub fn sleep(seconds: c_uint) -> c_uint { - unsafe { libc::sleep(seconds) } -} - -feature! { -#![feature = "acct"] - -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] -pub mod acct { - use crate::{Result, NixPath}; - use crate::errno::Errno; - use std::ptr; - - /// Enable process accounting - /// - /// See also [acct(2)](https://linux.die.net/man/2/acct) - pub fn enable<P: ?Sized + NixPath>(filename: &P) -> Result<()> { - let res = filename.with_nix_path(|cstr| { - unsafe { libc::acct(cstr.as_ptr()) } - })?; - - Errno::result(res).map(drop) - } - - /// Disable process accounting - pub fn disable() -> Result<()> { - let res = unsafe { libc::acct(ptr::null()) }; - - Errno::result(res).map(drop) - } -} -} - -feature! { -#![feature = "fs"] -/// Creates a regular file which persists even after process termination -/// -/// * `template`: a path whose 6 rightmost characters must be X, e.g. `/tmp/tmpfile_XXXXXX` -/// * returns: tuple of file descriptor and filename -/// -/// Err is returned either if no temporary filename could be created or the template doesn't -/// end with XXXXXX -/// -/// See also [mkstemp(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkstemp.html) -/// -/// # Example -/// -/// ```rust -/// use nix::unistd; -/// -/// let _ = match unistd::mkstemp("/tmp/tempfile_XXXXXX") { -/// Ok((fd, path)) => { -/// unistd::unlink(path.as_path()).unwrap(); // flag file to be deleted at app termination -/// fd -/// } -/// Err(e) => panic!("mkstemp failed: {}", e) -/// }; -/// // do something with fd -/// ``` -#[inline] -pub fn mkstemp<P: ?Sized + NixPath>(template: &P) -> Result<(RawFd, PathBuf)> { - let mut path = template.with_nix_path(|path| {path.to_bytes_with_nul().to_owned()})?; - let p = path.as_mut_ptr() as *mut _; - let fd = unsafe { libc::mkstemp(p) }; - let last = path.pop(); // drop the trailing nul - debug_assert!(last == Some(b'\0')); - let pathname = OsString::from_vec(path); - Errno::result(fd)?; - Ok((fd, PathBuf::from(pathname))) -} -} - -feature! { -#![all(feature = "fs", feature = "feature")] - -/// Variable names for `pathconf` -/// -/// Nix uses the same naming convention for these variables as the -/// [getconf(1)](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/getconf.html) utility. -/// That is, `PathconfVar` variables have the same name as the abstract -/// variables shown in the `pathconf(2)` man page. Usually, it's the same as -/// the C variable name without the leading `_PC_`. -/// -/// POSIX 1003.1-2008 standardizes all of these variables, but some OSes choose -/// not to implement variables that cannot change at runtime. -/// -/// # References -/// -/// - [pathconf(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html) -/// - [limits.h](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html) -/// - [unistd.h](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/unistd.h.html) -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -#[repr(i32)] -#[non_exhaustive] -pub enum PathconfVar { - #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "linux", - target_os = "netbsd", target_os = "openbsd", target_os = "redox"))] - /// Minimum number of bits needed to represent, as a signed integer value, - /// the maximum size of a regular file allowed in the specified directory. - #[cfg_attr(docsrs, doc(cfg(all())))] - FILESIZEBITS = libc::_PC_FILESIZEBITS, - /// Maximum number of links to a single file. - LINK_MAX = libc::_PC_LINK_MAX, - /// Maximum number of bytes in a terminal canonical input line. - MAX_CANON = libc::_PC_MAX_CANON, - /// Minimum number of bytes for which space is available in a terminal input - /// queue; therefore, the maximum number of bytes a conforming application - /// may require to be typed as input before reading them. - MAX_INPUT = libc::_PC_MAX_INPUT, - /// Maximum number of bytes in a filename (not including the terminating - /// null of a filename string). - NAME_MAX = libc::_PC_NAME_MAX, - /// Maximum number of bytes the implementation will store as a pathname in a - /// user-supplied buffer of unspecified size, including the terminating null - /// character. Minimum number the implementation will accept as the maximum - /// number of bytes in a pathname. - PATH_MAX = libc::_PC_PATH_MAX, - /// Maximum number of bytes that is guaranteed to be atomic when writing to - /// a pipe. - PIPE_BUF = libc::_PC_PIPE_BUF, - #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "illumos", - target_os = "linux", target_os = "netbsd", target_os = "openbsd", - target_os = "redox", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// Symbolic links can be created. - POSIX2_SYMLINKS = libc::_PC_2_SYMLINKS, - #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", - target_os = "linux", target_os = "openbsd", target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// Minimum number of bytes of storage actually allocated for any portion of - /// a file. - POSIX_ALLOC_SIZE_MIN = libc::_PC_ALLOC_SIZE_MIN, - #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", - target_os = "linux", target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// Recommended increment for file transfer sizes between the - /// `POSIX_REC_MIN_XFER_SIZE` and `POSIX_REC_MAX_XFER_SIZE` values. - POSIX_REC_INCR_XFER_SIZE = libc::_PC_REC_INCR_XFER_SIZE, - #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", - target_os = "linux", target_os = "openbsd", target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// Maximum recommended file transfer size. - POSIX_REC_MAX_XFER_SIZE = libc::_PC_REC_MAX_XFER_SIZE, - #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", - target_os = "linux", target_os = "openbsd", target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// Minimum recommended file transfer size. - POSIX_REC_MIN_XFER_SIZE = libc::_PC_REC_MIN_XFER_SIZE, - #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", - target_os = "linux", target_os = "openbsd", target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// Recommended file transfer buffer alignment. - POSIX_REC_XFER_ALIGN = libc::_PC_REC_XFER_ALIGN, - #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", - target_os = "illumos", target_os = "linux", target_os = "netbsd", - target_os = "openbsd", target_os = "redox", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// Maximum number of bytes in a symbolic link. - SYMLINK_MAX = libc::_PC_SYMLINK_MAX, - /// The use of `chown` and `fchown` is restricted to a process with - /// appropriate privileges, and to changing the group ID of a file only to - /// the effective group ID of the process or to one of its supplementary - /// group IDs. - _POSIX_CHOWN_RESTRICTED = libc::_PC_CHOWN_RESTRICTED, - /// Pathname components longer than {NAME_MAX} generate an error. - _POSIX_NO_TRUNC = libc::_PC_NO_TRUNC, - /// This symbol shall be defined to be the value of a character that shall - /// disable terminal special character handling. - _POSIX_VDISABLE = libc::_PC_VDISABLE, - #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", - target_os = "illumos", target_os = "linux", target_os = "openbsd", - target_os = "redox", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// Asynchronous input or output operations may be performed for the - /// associated file. - _POSIX_ASYNC_IO = libc::_PC_ASYNC_IO, - #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", - target_os = "illumos", target_os = "linux", target_os = "openbsd", - target_os = "redox", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// Prioritized input or output operations may be performed for the - /// associated file. - _POSIX_PRIO_IO = libc::_PC_PRIO_IO, - #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", - target_os = "illumos", target_os = "linux", target_os = "netbsd", - target_os = "openbsd", target_os = "redox", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// Synchronized input or output operations may be performed for the - /// associated file. - _POSIX_SYNC_IO = libc::_PC_SYNC_IO, - #[cfg(any(target_os = "dragonfly", target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The resolution in nanoseconds for all file timestamps. - _POSIX_TIMESTAMP_RESOLUTION = libc::_PC_TIMESTAMP_RESOLUTION -} - -/// Like `pathconf`, but works with file descriptors instead of paths (see -/// [fpathconf(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html)) -/// -/// # Parameters -/// -/// - `fd`: The file descriptor whose variable should be interrogated -/// - `var`: The pathconf variable to lookup -/// -/// # Returns -/// -/// - `Ok(Some(x))`: the variable's limit (for limit variables) or its -/// implementation level (for option variables). Implementation levels are -/// usually a decimal-coded date, such as 200112 for POSIX 2001.12 -/// - `Ok(None)`: the variable has no limit (for limit variables) or is -/// unsupported (for option variables) -/// - `Err(x)`: an error occurred -pub fn fpathconf(fd: RawFd, var: PathconfVar) -> Result<Option<c_long>> { - let raw = unsafe { - Errno::clear(); - libc::fpathconf(fd, var as c_int) - }; - if raw == -1 { - if errno::errno() == 0 { - Ok(None) - } else { - Err(Errno::last()) - } - } else { - Ok(Some(raw)) - } -} - -/// Get path-dependent configurable system variables (see -/// [pathconf(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html)) -/// -/// Returns the value of a path-dependent configurable system variable. Most -/// supported variables also have associated compile-time constants, but POSIX -/// allows their values to change at runtime. There are generally two types of -/// `pathconf` variables: options and limits. See [pathconf(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html) for more details. -/// -/// # Parameters -/// -/// - `path`: Lookup the value of `var` for this file or directory -/// - `var`: The `pathconf` variable to lookup -/// -/// # Returns -/// -/// - `Ok(Some(x))`: the variable's limit (for limit variables) or its -/// implementation level (for option variables). Implementation levels are -/// usually a decimal-coded date, such as 200112 for POSIX 2001.12 -/// - `Ok(None)`: the variable has no limit (for limit variables) or is -/// unsupported (for option variables) -/// - `Err(x)`: an error occurred -pub fn pathconf<P: ?Sized + NixPath>(path: &P, var: PathconfVar) -> Result<Option<c_long>> { - let raw = path.with_nix_path(|cstr| { - unsafe { - Errno::clear(); - libc::pathconf(cstr.as_ptr(), var as c_int) - } - })?; - if raw == -1 { - if errno::errno() == 0 { - Ok(None) - } else { - Err(Errno::last()) - } - } else { - Ok(Some(raw)) - } -} -} - -feature! { -#![feature = "feature"] - -/// Variable names for `sysconf` -/// -/// Nix uses the same naming convention for these variables as the -/// [getconf(1)](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/getconf.html) utility. -/// That is, `SysconfVar` variables have the same name as the abstract variables -/// shown in the `sysconf(3)` man page. Usually, it's the same as the C -/// variable name without the leading `_SC_`. -/// -/// All of these symbols are standardized by POSIX 1003.1-2008, but haven't been -/// implemented by all platforms. -/// -/// # References -/// -/// - [sysconf(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sysconf.html) -/// - [unistd.h](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/unistd.h.html) -/// - [limits.h](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html) -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -#[repr(i32)] -#[non_exhaustive] -pub enum SysconfVar { - /// Maximum number of I/O operations in a single list I/O call supported by - /// the implementation. - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - AIO_LISTIO_MAX = libc::_SC_AIO_LISTIO_MAX, - /// Maximum number of outstanding asynchronous I/O operations supported by - /// the implementation. - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - AIO_MAX = libc::_SC_AIO_MAX, - #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The maximum amount by which a process can decrease its asynchronous I/O - /// priority level from its own scheduling priority. - AIO_PRIO_DELTA_MAX = libc::_SC_AIO_PRIO_DELTA_MAX, - /// Maximum length of argument to the exec functions including environment data. - ARG_MAX = libc::_SC_ARG_MAX, - /// Maximum number of functions that may be registered with `atexit`. - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - ATEXIT_MAX = libc::_SC_ATEXIT_MAX, - /// Maximum obase values allowed by the bc utility. - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - BC_BASE_MAX = libc::_SC_BC_BASE_MAX, - /// Maximum number of elements permitted in an array by the bc utility. - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - BC_DIM_MAX = libc::_SC_BC_DIM_MAX, - /// Maximum scale value allowed by the bc utility. - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - BC_SCALE_MAX = libc::_SC_BC_SCALE_MAX, - /// Maximum length of a string constant accepted by the bc utility. - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - BC_STRING_MAX = libc::_SC_BC_STRING_MAX, - /// Maximum number of simultaneous processes per real user ID. - CHILD_MAX = libc::_SC_CHILD_MAX, - // The number of clock ticks per second. - CLK_TCK = libc::_SC_CLK_TCK, - /// Maximum number of weights that can be assigned to an entry of the - /// LC_COLLATE order keyword in the locale definition file - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - COLL_WEIGHTS_MAX = libc::_SC_COLL_WEIGHTS_MAX, - /// Maximum number of timer expiration overruns. - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - DELAYTIMER_MAX = libc::_SC_DELAYTIMER_MAX, - /// Maximum number of expressions that can be nested within parentheses by - /// the expr utility. - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - EXPR_NEST_MAX = libc::_SC_EXPR_NEST_MAX, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="netbsd", target_os="openbsd", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// Maximum length of a host name (not including the terminating null) as - /// returned from the `gethostname` function - HOST_NAME_MAX = libc::_SC_HOST_NAME_MAX, - /// Maximum number of iovec structures that one process has available for - /// use with `readv` or `writev`. - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IOV_MAX = libc::_SC_IOV_MAX, - /// Unless otherwise noted, the maximum length, in bytes, of a utility's - /// input line (either standard input or another file), when the utility is - /// described as processing text files. The length includes room for the - /// trailing newline. - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - LINE_MAX = libc::_SC_LINE_MAX, - /// Maximum length of a login name. - #[cfg(not(target_os = "haiku"))] - LOGIN_NAME_MAX = libc::_SC_LOGIN_NAME_MAX, - /// Maximum number of simultaneous supplementary group IDs per process. - NGROUPS_MAX = libc::_SC_NGROUPS_MAX, - /// Initial size of `getgrgid_r` and `getgrnam_r` data buffers - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - GETGR_R_SIZE_MAX = libc::_SC_GETGR_R_SIZE_MAX, - /// Initial size of `getpwuid_r` and `getpwnam_r` data buffers - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - GETPW_R_SIZE_MAX = libc::_SC_GETPW_R_SIZE_MAX, - /// The maximum number of open message queue descriptors a process may hold. - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MQ_OPEN_MAX = libc::_SC_MQ_OPEN_MAX, - /// The maximum number of message priorities supported by the implementation. - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - MQ_PRIO_MAX = libc::_SC_MQ_PRIO_MAX, - /// A value one greater than the maximum value that the system may assign to - /// a newly-created file descriptor. - OPEN_MAX = libc::_SC_OPEN_MAX, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports the Advisory Information option. - _POSIX_ADVISORY_INFO = libc::_SC_ADVISORY_INFO, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="netbsd", target_os="openbsd", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports barriers. - _POSIX_BARRIERS = libc::_SC_BARRIERS, - /// The implementation supports asynchronous input and output. - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX_ASYNCHRONOUS_IO = libc::_SC_ASYNCHRONOUS_IO, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="netbsd", target_os="openbsd", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports clock selection. - _POSIX_CLOCK_SELECTION = libc::_SC_CLOCK_SELECTION, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="netbsd", target_os="openbsd", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports the Process CPU-Time Clocks option. - _POSIX_CPUTIME = libc::_SC_CPUTIME, - /// The implementation supports the File Synchronization option. - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX_FSYNC = libc::_SC_FSYNC, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports the IPv6 option. - _POSIX_IPV6 = libc::_SC_IPV6, - /// The implementation supports job control. - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX_JOB_CONTROL = libc::_SC_JOB_CONTROL, - /// The implementation supports memory mapped Files. - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX_MAPPED_FILES = libc::_SC_MAPPED_FILES, - /// The implementation supports the Process Memory Locking option. - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX_MEMLOCK = libc::_SC_MEMLOCK, - /// The implementation supports the Range Memory Locking option. - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX_MEMLOCK_RANGE = libc::_SC_MEMLOCK_RANGE, - /// The implementation supports memory protection. - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX_MEMORY_PROTECTION = libc::_SC_MEMORY_PROTECTION, - /// The implementation supports the Message Passing option. - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX_MESSAGE_PASSING = libc::_SC_MESSAGE_PASSING, - /// The implementation supports the Monotonic Clock option. - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX_MONOTONIC_CLOCK = libc::_SC_MONOTONIC_CLOCK, - #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", - target_os = "illumos", target_os = "ios", target_os="linux", - target_os = "macos", target_os="openbsd", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports the Prioritized Input and Output option. - _POSIX_PRIORITIZED_IO = libc::_SC_PRIORITIZED_IO, - /// The implementation supports the Process Scheduling option. - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX_PRIORITY_SCHEDULING = libc::_SC_PRIORITY_SCHEDULING, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports the Raw Sockets option. - _POSIX_RAW_SOCKETS = libc::_SC_RAW_SOCKETS, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="netbsd", target_os="openbsd", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports read-write locks. - _POSIX_READER_WRITER_LOCKS = libc::_SC_READER_WRITER_LOCKS, - #[cfg(any(target_os = "android", target_os="dragonfly", target_os="freebsd", - target_os = "ios", target_os="linux", target_os = "macos", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports realtime signals. - _POSIX_REALTIME_SIGNALS = libc::_SC_REALTIME_SIGNALS, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="netbsd", target_os="openbsd", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports the Regular Expression Handling option. - _POSIX_REGEXP = libc::_SC_REGEXP, - /// Each process has a saved set-user-ID and a saved set-group-ID. - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX_SAVED_IDS = libc::_SC_SAVED_IDS, - /// The implementation supports semaphores. - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX_SEMAPHORES = libc::_SC_SEMAPHORES, - /// The implementation supports the Shared Memory Objects option. - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX_SHARED_MEMORY_OBJECTS = libc::_SC_SHARED_MEMORY_OBJECTS, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="netbsd", - target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports the POSIX shell. - _POSIX_SHELL = libc::_SC_SHELL, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="netbsd", - target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports the Spawn option. - _POSIX_SPAWN = libc::_SC_SPAWN, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="netbsd", - target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports spin locks. - _POSIX_SPIN_LOCKS = libc::_SC_SPIN_LOCKS, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports the Process Sporadic Server option. - _POSIX_SPORADIC_SERVER = libc::_SC_SPORADIC_SERVER, - #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX_SS_REPL_MAX = libc::_SC_SS_REPL_MAX, - /// The implementation supports the Synchronized Input and Output option. - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX_SYNCHRONIZED_IO = libc::_SC_SYNCHRONIZED_IO, - /// The implementation supports the Thread Stack Address Attribute option. - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX_THREAD_ATTR_STACKADDR = libc::_SC_THREAD_ATTR_STACKADDR, - /// The implementation supports the Thread Stack Size Attribute option. - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX_THREAD_ATTR_STACKSIZE = libc::_SC_THREAD_ATTR_STACKSIZE, - #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", - target_os="netbsd", target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports the Thread CPU-Time Clocks option. - _POSIX_THREAD_CPUTIME = libc::_SC_THREAD_CPUTIME, - /// The implementation supports the Non-Robust Mutex Priority Inheritance - /// option. - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX_THREAD_PRIO_INHERIT = libc::_SC_THREAD_PRIO_INHERIT, - /// The implementation supports the Non-Robust Mutex Priority Protection option. - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX_THREAD_PRIO_PROTECT = libc::_SC_THREAD_PRIO_PROTECT, - /// The implementation supports the Thread Execution Scheduling option. - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX_THREAD_PRIORITY_SCHEDULING = libc::_SC_THREAD_PRIORITY_SCHEDULING, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="netbsd", - target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports the Thread Process-Shared Synchronization - /// option. - _POSIX_THREAD_PROCESS_SHARED = libc::_SC_THREAD_PROCESS_SHARED, - #[cfg(any(target_os="dragonfly", target_os="linux", target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports the Robust Mutex Priority Inheritance option. - _POSIX_THREAD_ROBUST_PRIO_INHERIT = libc::_SC_THREAD_ROBUST_PRIO_INHERIT, - #[cfg(any(target_os="dragonfly", target_os="linux", target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports the Robust Mutex Priority Protection option. - _POSIX_THREAD_ROBUST_PRIO_PROTECT = libc::_SC_THREAD_ROBUST_PRIO_PROTECT, - /// The implementation supports thread-safe functions. - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX_THREAD_SAFE_FUNCTIONS = libc::_SC_THREAD_SAFE_FUNCTIONS, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports the Thread Sporadic Server option. - _POSIX_THREAD_SPORADIC_SERVER = libc::_SC_THREAD_SPORADIC_SERVER, - /// The implementation supports threads. - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX_THREADS = libc::_SC_THREADS, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports timeouts. - _POSIX_TIMEOUTS = libc::_SC_TIMEOUTS, - /// The implementation supports timers. - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX_TIMERS = libc::_SC_TIMERS, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports the Trace option. - _POSIX_TRACE = libc::_SC_TRACE, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports the Trace Event Filter option. - _POSIX_TRACE_EVENT_FILTER = libc::_SC_TRACE_EVENT_FILTER, - #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX_TRACE_EVENT_NAME_MAX = libc::_SC_TRACE_EVENT_NAME_MAX, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports the Trace Inherit option. - _POSIX_TRACE_INHERIT = libc::_SC_TRACE_INHERIT, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports the Trace Log option. - _POSIX_TRACE_LOG = libc::_SC_TRACE_LOG, - #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX_TRACE_NAME_MAX = libc::_SC_TRACE_NAME_MAX, - #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX_TRACE_SYS_MAX = libc::_SC_TRACE_SYS_MAX, - #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX_TRACE_USER_EVENT_MAX = libc::_SC_TRACE_USER_EVENT_MAX, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports the Typed Memory Objects option. - _POSIX_TYPED_MEMORY_OBJECTS = libc::_SC_TYPED_MEMORY_OBJECTS, - /// Integer value indicating version of this standard (C-language binding) - /// to which the implementation conforms. For implementations conforming to - /// POSIX.1-2008, the value shall be 200809L. - _POSIX_VERSION = libc::_SC_VERSION, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="netbsd", - target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation provides a C-language compilation environment with - /// 32-bit `int`, `long`, `pointer`, and `off_t` types. - _POSIX_V6_ILP32_OFF32 = libc::_SC_V6_ILP32_OFF32, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="netbsd", - target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation provides a C-language compilation environment with - /// 32-bit `int`, `long`, and pointer types and an `off_t` type using at - /// least 64 bits. - _POSIX_V6_ILP32_OFFBIG = libc::_SC_V6_ILP32_OFFBIG, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="netbsd", - target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation provides a C-language compilation environment with - /// 32-bit `int` and 64-bit `long`, `pointer`, and `off_t` types. - _POSIX_V6_LP64_OFF64 = libc::_SC_V6_LP64_OFF64, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="netbsd", - target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation provides a C-language compilation environment with an - /// `int` type using at least 32 bits and `long`, pointer, and `off_t` types - /// using at least 64 bits. - _POSIX_V6_LPBIG_OFFBIG = libc::_SC_V6_LPBIG_OFFBIG, - /// The implementation supports the C-Language Binding option. - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX2_C_BIND = libc::_SC_2_C_BIND, - /// The implementation supports the C-Language Development Utilities option. - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX2_C_DEV = libc::_SC_2_C_DEV, - /// The implementation supports the Terminal Characteristics option. - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX2_CHAR_TERM = libc::_SC_2_CHAR_TERM, - /// The implementation supports the FORTRAN Development Utilities option. - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX2_FORT_DEV = libc::_SC_2_FORT_DEV, - /// The implementation supports the FORTRAN Runtime Utilities option. - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX2_FORT_RUN = libc::_SC_2_FORT_RUN, - /// The implementation supports the creation of locales by the localedef - /// utility. - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX2_LOCALEDEF = libc::_SC_2_LOCALEDEF, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="netbsd", - target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports the Batch Environment Services and Utilities - /// option. - _POSIX2_PBS = libc::_SC_2_PBS, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="netbsd", - target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports the Batch Accounting option. - _POSIX2_PBS_ACCOUNTING = libc::_SC_2_PBS_ACCOUNTING, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="netbsd", - target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports the Batch Checkpoint/Restart option. - _POSIX2_PBS_CHECKPOINT = libc::_SC_2_PBS_CHECKPOINT, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="netbsd", - target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports the Locate Batch Job Request option. - _POSIX2_PBS_LOCATE = libc::_SC_2_PBS_LOCATE, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="netbsd", - target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports the Batch Job Message Request option. - _POSIX2_PBS_MESSAGE = libc::_SC_2_PBS_MESSAGE, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="netbsd", - target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports the Track Batch Job Request option. - _POSIX2_PBS_TRACK = libc::_SC_2_PBS_TRACK, - /// The implementation supports the Software Development Utilities option. - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX2_SW_DEV = libc::_SC_2_SW_DEV, - /// The implementation supports the User Portability Utilities option. - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX2_UPE = libc::_SC_2_UPE, - /// Integer value indicating version of the Shell and Utilities volume of - /// POSIX.1 to which the implementation conforms. - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _POSIX2_VERSION = libc::_SC_2_VERSION, - /// The size of a system page in bytes. - /// - /// POSIX also defines an alias named `PAGESIZE`, but Rust does not allow two - /// enum constants to have the same value, so nix omits `PAGESIZE`. - PAGE_SIZE = libc::_SC_PAGE_SIZE, - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - PTHREAD_DESTRUCTOR_ITERATIONS = libc::_SC_THREAD_DESTRUCTOR_ITERATIONS, - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - PTHREAD_KEYS_MAX = libc::_SC_THREAD_KEYS_MAX, - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - PTHREAD_STACK_MIN = libc::_SC_THREAD_STACK_MIN, - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - PTHREAD_THREADS_MAX = libc::_SC_THREAD_THREADS_MAX, - #[cfg(not(target_os = "haiku"))] - RE_DUP_MAX = libc::_SC_RE_DUP_MAX, - #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - RTSIG_MAX = libc::_SC_RTSIG_MAX, - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - SEM_NSEMS_MAX = libc::_SC_SEM_NSEMS_MAX, - #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - SEM_VALUE_MAX = libc::_SC_SEM_VALUE_MAX, - #[cfg(any(target_os = "android", target_os="dragonfly", target_os="freebsd", - target_os = "ios", target_os="linux", target_os = "macos", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - SIGQUEUE_MAX = libc::_SC_SIGQUEUE_MAX, - STREAM_MAX = libc::_SC_STREAM_MAX, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="netbsd", - target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - SYMLOOP_MAX = libc::_SC_SYMLOOP_MAX, - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - TIMER_MAX = libc::_SC_TIMER_MAX, - TTY_NAME_MAX = libc::_SC_TTY_NAME_MAX, - TZNAME_MAX = libc::_SC_TZNAME_MAX, - #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports the X/Open Encryption Option Group. - _XOPEN_CRYPT = libc::_SC_XOPEN_CRYPT, - #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports the Issue 4, Version 2 Enhanced - /// Internationalization Option Group. - _XOPEN_ENH_I18N = libc::_SC_XOPEN_ENH_I18N, - #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _XOPEN_LEGACY = libc::_SC_XOPEN_LEGACY, - #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports the X/Open Realtime Option Group. - _XOPEN_REALTIME = libc::_SC_XOPEN_REALTIME, - #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports the X/Open Realtime Threads Option Group. - _XOPEN_REALTIME_THREADS = libc::_SC_XOPEN_REALTIME_THREADS, - /// The implementation supports the Issue 4, Version 2 Shared Memory Option - /// Group. - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - _XOPEN_SHM = libc::_SC_XOPEN_SHM, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports the XSI STREAMS Option Group. - _XOPEN_STREAMS = libc::_SC_XOPEN_STREAMS, - #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// The implementation supports the XSI option - _XOPEN_UNIX = libc::_SC_XOPEN_UNIX, - #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - /// Integer value indicating version of the X/Open Portability Guide to - /// which the implementation conforms. - _XOPEN_VERSION = libc::_SC_XOPEN_VERSION, - /// The number of pages of physical memory. Note that it is possible for - /// the product of this value to overflow. - #[cfg(any(target_os="android", target_os="linux"))] - _PHYS_PAGES = libc::_SC_PHYS_PAGES, - /// The number of currently available pages of physical memory. - #[cfg(any(target_os="android", target_os="linux"))] - _AVPHYS_PAGES = libc::_SC_AVPHYS_PAGES, - /// The number of processors configured. - #[cfg(any(target_os="android", target_os="linux"))] - _NPROCESSORS_CONF = libc::_SC_NPROCESSORS_CONF, - /// The number of processors currently online (available). - #[cfg(any(target_os="android", target_os="linux"))] - _NPROCESSORS_ONLN = libc::_SC_NPROCESSORS_ONLN, -} - -/// Get configurable system variables (see -/// [sysconf(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sysconf.html)) -/// -/// Returns the value of a configurable system variable. Most supported -/// variables also have associated compile-time constants, but POSIX -/// allows their values to change at runtime. There are generally two types of -/// sysconf variables: options and limits. See sysconf(3) for more details. -/// -/// # Returns -/// -/// - `Ok(Some(x))`: the variable's limit (for limit variables) or its -/// implementation level (for option variables). Implementation levels are -/// usually a decimal-coded date, such as 200112 for POSIX 2001.12 -/// - `Ok(None)`: the variable has no limit (for limit variables) or is -/// unsupported (for option variables) -/// - `Err(x)`: an error occurred -pub fn sysconf(var: SysconfVar) -> Result<Option<c_long>> { - let raw = unsafe { - Errno::clear(); - libc::sysconf(var as c_int) - }; - if raw == -1 { - if errno::errno() == 0 { - Ok(None) - } else { - Err(Errno::last()) - } - } else { - Ok(Some(raw)) - } -} -} - -feature! { -#![feature = "fs"] - -#[cfg(any(target_os = "android", target_os = "linux"))] -mod pivot_root { - use crate::{Result, NixPath}; - use crate::errno::Errno; - - pub fn pivot_root<P1: ?Sized + NixPath, P2: ?Sized + NixPath>( - new_root: &P1, put_old: &P2) -> Result<()> { - let res = new_root.with_nix_path(|new_root| { - put_old.with_nix_path(|put_old| { - unsafe { - libc::syscall(libc::SYS_pivot_root, new_root.as_ptr(), put_old.as_ptr()) - } - }) - })??; - - Errno::result(res).map(drop) - } -} -} - -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd" -))] -mod setres { - feature! { - #![feature = "user"] - - use crate::Result; - use crate::errno::Errno; - use super::{Uid, Gid}; - - /// Sets the real, effective, and saved uid. - /// ([see setresuid(2)](https://man7.org/linux/man-pages/man2/setresuid.2.html)) - /// - /// * `ruid`: real user id - /// * `euid`: effective user id - /// * `suid`: saved user id - /// * returns: Ok or libc error code. - /// - /// Err is returned if the user doesn't have permission to set this UID. - #[inline] - pub fn setresuid(ruid: Uid, euid: Uid, suid: Uid) -> Result<()> { - let res = unsafe { libc::setresuid(ruid.into(), euid.into(), suid.into()) }; - - Errno::result(res).map(drop) - } - - /// Sets the real, effective, and saved gid. - /// ([see setresuid(2)](https://man7.org/linux/man-pages/man2/setresuid.2.html)) - /// - /// * `rgid`: real group id - /// * `egid`: effective group id - /// * `sgid`: saved group id - /// * returns: Ok or libc error code. - /// - /// Err is returned if the user doesn't have permission to set this GID. - #[inline] - pub fn setresgid(rgid: Gid, egid: Gid, sgid: Gid) -> Result<()> { - let res = unsafe { libc::setresgid(rgid.into(), egid.into(), sgid.into()) }; - - Errno::result(res).map(drop) - } - } -} - -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd" -))] -mod getres { - feature! { - #![feature = "user"] - - use crate::Result; - use crate::errno::Errno; - use super::{Uid, Gid}; - - /// Real, effective and saved user IDs. - #[derive(Debug, Copy, Clone, Eq, PartialEq)] - pub struct ResUid { - pub real: Uid, - pub effective: Uid, - pub saved: Uid - } - - /// Real, effective and saved group IDs. - #[derive(Debug, Copy, Clone, Eq, PartialEq)] - pub struct ResGid { - pub real: Gid, - pub effective: Gid, - pub saved: Gid - } - - /// Gets the real, effective, and saved user IDs. - /// - /// ([see getresuid(2)](http://man7.org/linux/man-pages/man2/getresuid.2.html)) - /// - /// #Returns - /// - /// - `Ok((Uid, Uid, Uid))`: tuple of real, effective and saved uids on success. - /// - `Err(x)`: libc error code on failure. - /// - #[inline] - pub fn getresuid() -> Result<ResUid> { - let mut ruid = libc::uid_t::max_value(); - let mut euid = libc::uid_t::max_value(); - let mut suid = libc::uid_t::max_value(); - let res = unsafe { libc::getresuid(&mut ruid, &mut euid, &mut suid) }; - - Errno::result(res).map(|_| ResUid{ real: Uid(ruid), effective: Uid(euid), saved: Uid(suid) }) - } - - /// Gets the real, effective, and saved group IDs. - /// - /// ([see getresgid(2)](http://man7.org/linux/man-pages/man2/getresgid.2.html)) - /// - /// #Returns - /// - /// - `Ok((Gid, Gid, Gid))`: tuple of real, effective and saved gids on success. - /// - `Err(x)`: libc error code on failure. - /// - #[inline] - pub fn getresgid() -> Result<ResGid> { - let mut rgid = libc::gid_t::max_value(); - let mut egid = libc::gid_t::max_value(); - let mut sgid = libc::gid_t::max_value(); - let res = unsafe { libc::getresgid(&mut rgid, &mut egid, &mut sgid) }; - - Errno::result(res).map(|_| ResGid { real: Gid(rgid), effective: Gid(egid), saved: Gid(sgid) } ) - } - } -} - -#[cfg(feature = "fs")] -libc_bitflags! { - /// Options for access() - #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] - pub struct AccessFlags : c_int { - /// Test for existence of file. - F_OK; - /// Test for read permission. - R_OK; - /// Test for write permission. - W_OK; - /// Test for execute (search) permission. - X_OK; - } -} - -feature! { -#![feature = "fs"] - -/// Checks the file named by `path` for accessibility according to the flags given by `amode` -/// See [access(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/access.html) -pub fn access<P: ?Sized + NixPath>(path: &P, amode: AccessFlags) -> Result<()> { - let res = path.with_nix_path(|cstr| { - unsafe { - libc::access(cstr.as_ptr(), amode.bits) - } - })?; - Errno::result(res).map(drop) -} - -/// Checks the file named by `path` for accessibility according to the flags given by `mode` -/// -/// If `dirfd` has a value, then `path` is relative to directory associated with the file descriptor. -/// -/// If `dirfd` is `None`, then `path` is relative to the current working directory. -/// -/// # References -/// -/// [faccessat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/faccessat.html) -// redox: does not appear to support the *at family of syscalls. -#[cfg(not(target_os = "redox"))] -pub fn faccessat<P: ?Sized + NixPath>(dirfd: Option<RawFd>, path: &P, mode: AccessFlags, flags: AtFlags) -> Result<()> { - let res = path.with_nix_path(|cstr| { - unsafe { - libc::faccessat(at_rawfd(dirfd), cstr.as_ptr(), mode.bits(), flags.bits()) - } - })?; - Errno::result(res).map(drop) -} - -/// Checks the file named by `path` for accessibility according to the flags given -/// by `mode` using effective UID, effective GID and supplementary group lists. -/// -/// # References -/// -/// * [FreeBSD man page](https://www.freebsd.org/cgi/man.cgi?query=eaccess&sektion=2&n=1) -/// * [Linux man page](https://man7.org/linux/man-pages/man3/euidaccess.3.html) -#[cfg(any( - all(target_os = "linux", not(target_env = "uclibc")), - target_os = "freebsd", - target_os = "dragonfly" -))] -pub fn eaccess<P: ?Sized + NixPath>(path: &P, mode: AccessFlags) -> Result<()> { - let res = path.with_nix_path(|cstr| { - unsafe { - libc::eaccess(cstr.as_ptr(), mode.bits) - } - })?; - Errno::result(res).map(drop) -} -} - -feature! { -#![feature = "user"] - -/// Representation of a User, based on `libc::passwd` -/// -/// The reason some fields in this struct are `String` and others are `CString` is because some -/// fields are based on the user's locale, which could be non-UTF8, while other fields are -/// guaranteed to conform to [`NAME_REGEX`](https://serverfault.com/a/73101/407341), which only -/// contains ASCII. -#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct User { - /// Username - pub name: String, - /// User password (probably hashed) - pub passwd: CString, - /// User ID - pub uid: Uid, - /// Group ID - pub gid: Gid, - /// User information - #[cfg(not(all(target_os = "android", target_pointer_width = "32")))] - pub gecos: CString, - /// Home directory - pub dir: PathBuf, - /// Path to shell - pub shell: PathBuf, - /// Login class - #[cfg(not(any(target_os = "android", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub class: CString, - /// Last password change - #[cfg(not(any(target_os = "android", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub change: libc::time_t, - /// Expiration time of account - #[cfg(not(any(target_os = "android", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris")))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub expire: libc::time_t -} - -#[cfg(not(target_os = "redox"))] //RedoxFS does not support passwd -impl From<&libc::passwd> for User { - fn from(pw: &libc::passwd) -> User { - unsafe { - User { - name: if pw.pw_name.is_null() { Default::default() } else { CStr::from_ptr(pw.pw_name).to_string_lossy().into_owned() }, - passwd: if pw.pw_passwd.is_null() { Default::default() } else { CString::new(CStr::from_ptr(pw.pw_passwd).to_bytes()).unwrap() }, - #[cfg(not(all(target_os = "android", target_pointer_width = "32")))] - gecos: if pw.pw_gecos.is_null() { Default::default() } else { CString::new(CStr::from_ptr(pw.pw_gecos).to_bytes()).unwrap() }, - dir: if pw.pw_dir.is_null() { Default::default() } else { PathBuf::from(OsStr::from_bytes(CStr::from_ptr(pw.pw_dir).to_bytes())) }, - shell: if pw.pw_shell.is_null() { Default::default() } else { PathBuf::from(OsStr::from_bytes(CStr::from_ptr(pw.pw_shell).to_bytes())) }, - uid: Uid::from_raw(pw.pw_uid), - gid: Gid::from_raw(pw.pw_gid), - #[cfg(not(any(target_os = "android", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris")))] - class: CString::new(CStr::from_ptr(pw.pw_class).to_bytes()).unwrap(), - #[cfg(not(any(target_os = "android", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris")))] - change: pw.pw_change, - #[cfg(not(any(target_os = "android", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris")))] - expire: pw.pw_expire - } - } - } -} - -#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd -impl From<User> for libc::passwd { - fn from(u: User) -> Self { - let name = match CString::new(u.name) { - Ok(n) => n.into_raw(), - Err(_) => CString::new("").unwrap().into_raw(), - }; - let dir = match u.dir.into_os_string().into_string() { - Ok(s) => CString::new(s.as_str()).unwrap().into_raw(), - Err(_) => CString::new("").unwrap().into_raw(), - }; - let shell = match u.shell.into_os_string().into_string() { - Ok(s) => CString::new(s.as_str()).unwrap().into_raw(), - Err(_) => CString::new("").unwrap().into_raw(), - }; - Self { - pw_name: name, - pw_passwd: u.passwd.into_raw(), - #[cfg(not(all(target_os = "android", target_pointer_width = "32")))] - pw_gecos: u.gecos.into_raw(), - pw_dir: dir, - pw_shell: shell, - pw_uid: u.uid.0, - pw_gid: u.gid.0, - #[cfg(not(any(target_os = "android", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris")))] - pw_class: u.class.into_raw(), - #[cfg(not(any(target_os = "android", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris")))] - pw_change: u.change, - #[cfg(not(any(target_os = "android", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris")))] - pw_expire: u.expire, - #[cfg(target_os = "illumos")] - pw_age: CString::new("").unwrap().into_raw(), - #[cfg(target_os = "illumos")] - pw_comment: CString::new("").unwrap().into_raw(), - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - pw_fields: 0, - } - } -} - -#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd -impl User { - fn from_anything<F>(f: F) -> Result<Option<Self>> - where - F: Fn(*mut libc::passwd, - *mut c_char, - libc::size_t, - *mut *mut libc::passwd) -> libc::c_int - { - let buflimit = 1048576; - let bufsize = match sysconf(SysconfVar::GETPW_R_SIZE_MAX) { - Ok(Some(n)) => n as usize, - Ok(None) | Err(_) => 16384, - }; - - let mut cbuf = Vec::with_capacity(bufsize); - let mut pwd = mem::MaybeUninit::<libc::passwd>::uninit(); - let mut res = ptr::null_mut(); - - loop { - let error = f(pwd.as_mut_ptr(), cbuf.as_mut_ptr(), cbuf.capacity(), &mut res); - if error == 0 { - if res.is_null() { - return Ok(None); - } else { - let pwd = unsafe { pwd.assume_init() }; - return Ok(Some(User::from(&pwd))); - } - } else if Errno::last() == Errno::ERANGE { - // Trigger the internal buffer resizing logic. - reserve_double_buffer_size(&mut cbuf, buflimit)?; - } else { - return Err(Errno::last()); - } - } - } - - /// Get a user by UID. - /// - /// Internally, this function calls - /// [getpwuid_r(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html) - /// - /// # Examples - /// - /// ``` - /// use nix::unistd::{Uid, User}; - /// // Returns an Result<Option<User>>, thus the double unwrap. - /// let res = User::from_uid(Uid::from_raw(0)).unwrap().unwrap(); - /// assert_eq!(res.name, "root"); - /// ``` - pub fn from_uid(uid: Uid) -> Result<Option<Self>> { - User::from_anything(|pwd, cbuf, cap, res| { - unsafe { libc::getpwuid_r(uid.0, pwd, cbuf, cap, res) } - }) - } - - /// Get a user by name. - /// - /// Internally, this function calls - /// [getpwnam_r(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html) - /// - /// # Examples - /// - /// ``` - /// use nix::unistd::User; - /// // Returns an Result<Option<User>>, thus the double unwrap. - /// let res = User::from_name("root").unwrap().unwrap(); - /// assert_eq!(res.name, "root"); - /// ``` - pub fn from_name(name: &str) -> Result<Option<Self>> { - let name = match CString::new(name) { - Ok(c_str) => c_str, - Err(_nul_error) => return Ok(None), - }; - User::from_anything(|pwd, cbuf, cap, res| { - unsafe { libc::getpwnam_r(name.as_ptr(), pwd, cbuf, cap, res) } - }) - } -} - -/// Representation of a Group, based on `libc::group` -#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct Group { - /// Group name - pub name: String, - /// Group password - pub passwd: CString, - /// Group ID - pub gid: Gid, - /// List of Group members - pub mem: Vec<String> -} - -#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd -impl From<&libc::group> for Group { - fn from(gr: &libc::group) -> Group { - unsafe { - Group { - name: CStr::from_ptr(gr.gr_name).to_string_lossy().into_owned(), - passwd: CString::new(CStr::from_ptr(gr.gr_passwd).to_bytes()).unwrap(), - gid: Gid::from_raw(gr.gr_gid), - mem: Group::members(gr.gr_mem) - } - } - } -} - -#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd -impl Group { - unsafe fn members(mem: *mut *mut c_char) -> Vec<String> { - let mut ret = Vec::new(); - - for i in 0.. { - let u = mem.offset(i); - if (*u).is_null() { - break; - } else { - let s = CStr::from_ptr(*u).to_string_lossy().into_owned(); - ret.push(s); - } - } - - ret - } - - fn from_anything<F>(f: F) -> Result<Option<Self>> - where - F: Fn(*mut libc::group, - *mut c_char, - libc::size_t, - *mut *mut libc::group) -> libc::c_int - { - let buflimit = 1048576; - let bufsize = match sysconf(SysconfVar::GETGR_R_SIZE_MAX) { - Ok(Some(n)) => n as usize, - Ok(None) | Err(_) => 16384, - }; - - let mut cbuf = Vec::with_capacity(bufsize); - let mut grp = mem::MaybeUninit::<libc::group>::uninit(); - let mut res = ptr::null_mut(); - - loop { - let error = f(grp.as_mut_ptr(), cbuf.as_mut_ptr(), cbuf.capacity(), &mut res); - if error == 0 { - if res.is_null() { - return Ok(None); - } else { - let grp = unsafe { grp.assume_init() }; - return Ok(Some(Group::from(&grp))); - } - } else if Errno::last() == Errno::ERANGE { - // Trigger the internal buffer resizing logic. - reserve_double_buffer_size(&mut cbuf, buflimit)?; - } else { - return Err(Errno::last()); - } - } - } - - /// Get a group by GID. - /// - /// Internally, this function calls - /// [getgrgid_r(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html) - /// - /// # Examples - /// - // Disable this test on all OS except Linux as root group may not exist. - #[cfg_attr(not(target_os = "linux"), doc = " ```no_run")] - #[cfg_attr(target_os = "linux", doc = " ```")] - /// use nix::unistd::{Gid, Group}; - /// // Returns an Result<Option<Group>>, thus the double unwrap. - /// let res = Group::from_gid(Gid::from_raw(0)).unwrap().unwrap(); - /// assert!(res.name == "root"); - /// ``` - pub fn from_gid(gid: Gid) -> Result<Option<Self>> { - Group::from_anything(|grp, cbuf, cap, res| { - unsafe { libc::getgrgid_r(gid.0, grp, cbuf, cap, res) } - }) - } - - /// Get a group by name. - /// - /// Internally, this function calls - /// [getgrnam_r(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html) - /// - /// # Examples - /// - // Disable this test on all OS except Linux as root group may not exist. - #[cfg_attr(not(target_os = "linux"), doc = " ```no_run")] - #[cfg_attr(target_os = "linux", doc = " ```")] - /// use nix::unistd::Group; - /// // Returns an Result<Option<Group>>, thus the double unwrap. - /// let res = Group::from_name("root").unwrap().unwrap(); - /// assert!(res.name == "root"); - /// ``` - pub fn from_name(name: &str) -> Result<Option<Self>> { - let name = match CString::new(name) { - Ok(c_str) => c_str, - Err(_nul_error) => return Ok(None), - }; - Group::from_anything(|grp, cbuf, cap, res| { - unsafe { libc::getgrnam_r(name.as_ptr(), grp, cbuf, cap, res) } - }) - } -} -} - -feature! { -#![feature = "term"] - -/// Get the name of the terminal device that is open on file descriptor fd -/// (see [`ttyname(3)`](https://man7.org/linux/man-pages/man3/ttyname.3.html)). -#[cfg(not(target_os = "fuchsia"))] -pub fn ttyname(fd: RawFd) -> Result<PathBuf> { - const PATH_MAX: usize = libc::PATH_MAX as usize; - let mut buf = vec![0_u8; PATH_MAX]; - let c_buf = buf.as_mut_ptr() as *mut libc::c_char; - - let ret = unsafe { libc::ttyname_r(fd, c_buf, buf.len()) }; - if ret != 0 { - return Err(Errno::from_i32(ret)); - } - - let nul = buf.iter().position(|c| *c == b'\0').unwrap(); - buf.truncate(nul); - Ok(OsString::from_vec(buf).into()) -} -} - -feature! { -#![all(feature = "socket", feature = "user")] - -/// Get the effective user ID and group ID associated with a Unix domain socket. -/// -/// See also [getpeereid(3)](https://www.freebsd.org/cgi/man.cgi?query=getpeereid) -#[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "dragonfly", -))] -pub fn getpeereid(fd: RawFd) -> Result<(Uid, Gid)> { - let mut uid = 1; - let mut gid = 1; - - let ret = unsafe { libc::getpeereid(fd, &mut uid, &mut gid) }; - - Errno::result(ret).map(|_| (Uid(uid), Gid(gid))) -} -} - -feature! { -#![all(feature = "fs")] - -/// Set the file flags. -/// -/// See also [chflags(2)](https://www.freebsd.org/cgi/man.cgi?query=chflags&sektion=2) -#[cfg(any( - target_os = "openbsd", - target_os = "netbsd", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "macos", - target_os = "ios" -))] -pub fn chflags<P: ?Sized + NixPath>(path: &P, flags: FileFlag) -> Result<()> { - let res = path.with_nix_path(|cstr| unsafe { - libc::chflags(cstr.as_ptr(), flags.bits()) - })?; - - Errno::result(res).map(drop) -} -} diff --git a/vendor/nix/test/common/mod.rs b/vendor/nix/test/common/mod.rs deleted file mode 100644 index bb056aab8..000000000 --- a/vendor/nix/test/common/mod.rs +++ /dev/null @@ -1,149 +0,0 @@ -use cfg_if::cfg_if; - -#[macro_export] -macro_rules! skip { - ($($reason: expr),+) => { - use ::std::io::{self, Write}; - - let stderr = io::stderr(); - let mut handle = stderr.lock(); - writeln!(handle, $($reason),+).unwrap(); - return; - } -} - -cfg_if! { - if #[cfg(any(target_os = "android", target_os = "linux"))] { - #[macro_export] macro_rules! require_capability { - ($name:expr, $capname:ident) => { - use ::caps::{Capability, CapSet, has_cap}; - - if !has_cap(None, CapSet::Effective, Capability::$capname) - .unwrap() - { - skip!("{} requires capability {}. Skipping test.", $name, Capability::$capname); - } - } - } - } else if #[cfg(not(target_os = "redox"))] { - #[macro_export] macro_rules! require_capability { - ($name:expr, $capname:ident) => {} - } - } -} - -/// Skip the test if we don't have the ability to mount file systems. -#[cfg(target_os = "freebsd")] -#[macro_export] -macro_rules! require_mount { - ($name:expr) => { - use ::sysctl::{CtlValue, Sysctl}; - use nix::unistd::Uid; - - let ctl = ::sysctl::Ctl::new("vfs.usermount").unwrap(); - if !Uid::current().is_root() && CtlValue::Int(0) == ctl.value().unwrap() - { - skip!( - "{} requires the ability to mount file systems. Skipping test.", - $name - ); - } - }; -} - -#[cfg(any(target_os = "linux", target_os = "android"))] -#[macro_export] -macro_rules! skip_if_cirrus { - ($reason:expr) => { - if std::env::var_os("CIRRUS_CI").is_some() { - skip!("{}", $reason); - } - }; -} - -#[cfg(target_os = "freebsd")] -#[macro_export] -macro_rules! skip_if_jailed { - ($name:expr) => { - use ::sysctl::{CtlValue, Sysctl}; - - let ctl = ::sysctl::Ctl::new("security.jail.jailed").unwrap(); - if let CtlValue::Int(1) = ctl.value().unwrap() { - skip!("{} cannot run in a jail. Skipping test.", $name); - } - }; -} - -#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] -#[macro_export] -macro_rules! skip_if_not_root { - ($name:expr) => { - use nix::unistd::Uid; - - if !Uid::current().is_root() { - skip!("{} requires root privileges. Skipping test.", $name); - } - }; -} - -cfg_if! { - if #[cfg(any(target_os = "android", target_os = "linux"))] { - #[macro_export] macro_rules! skip_if_seccomp { - ($name:expr) => { - if let Ok(s) = std::fs::read_to_string("/proc/self/status") { - for l in s.lines() { - let mut fields = l.split_whitespace(); - if fields.next() == Some("Seccomp:") && - fields.next() != Some("0") - { - skip!("{} cannot be run in Seccomp mode. Skipping test.", - stringify!($name)); - } - } - } - } - } - } else if #[cfg(not(target_os = "redox"))] { - #[macro_export] macro_rules! skip_if_seccomp { - ($name:expr) => {} - } - } -} - -cfg_if! { - if #[cfg(target_os = "linux")] { - #[macro_export] macro_rules! require_kernel_version { - ($name:expr, $version_requirement:expr) => { - use semver::{Version, VersionReq}; - - let version_requirement = VersionReq::parse($version_requirement) - .expect("Bad match_version provided"); - - let uname = nix::sys::utsname::uname().unwrap(); - println!("{}", uname.sysname().to_str().unwrap()); - println!("{}", uname.nodename().to_str().unwrap()); - println!("{}", uname.release().to_str().unwrap()); - println!("{}", uname.version().to_str().unwrap()); - println!("{}", uname.machine().to_str().unwrap()); - - // Fix stuff that the semver parser can't handle - let fixed_release = &uname.release().to_str().unwrap().to_string() - // Fedora 33 reports version as 4.18.el8_2.x86_64 or - // 5.18.200-fc33.x86_64. Remove the underscore. - .replace("_", "-") - // Cirrus-CI reports version as 4.19.112+ . Remove the + - .replace("+", ""); - let mut version = Version::parse(fixed_release).unwrap(); - - //Keep only numeric parts - version.pre = semver::Prerelease::EMPTY; - version.build = semver::BuildMetadata::EMPTY; - - if !version_requirement.matches(&version) { - skip!("Skip {} because kernel version `{}` doesn't match the requirement `{}`", - stringify!($name), version, version_requirement); - } - } - } - } -} diff --git a/vendor/nix/test/sys/mod.rs b/vendor/nix/test/sys/mod.rs deleted file mode 100644 index 20312120a..000000000 --- a/vendor/nix/test/sys/mod.rs +++ /dev/null @@ -1,60 +0,0 @@ -mod test_signal; - -// NOTE: DragonFly lacks a kernel-level implementation of Posix AIO as of -// this writing. There is an user-level implementation, but whether aio -// works or not heavily depends on which pthread implementation is chosen -// by the user at link time. For this reason we do not want to run aio test -// cases on DragonFly. -#[cfg(any( - target_os = "freebsd", - target_os = "ios", - all(target_os = "linux", not(target_env = "uclibc")), - target_os = "macos", - target_os = "netbsd" -))] -mod test_aio; -#[cfg(not(any( - target_os = "redox", - target_os = "fuchsia", - target_os = "haiku" -)))] -mod test_ioctl; -#[cfg(not(target_os = "redox"))] -mod test_mman; -#[cfg(not(target_os = "redox"))] -mod test_select; -#[cfg(target_os = "linux")] -mod test_signalfd; -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] -mod test_socket; -#[cfg(not(any(target_os = "redox")))] -mod test_sockopt; -mod test_stat; -#[cfg(any(target_os = "android", target_os = "linux"))] -mod test_sysinfo; -#[cfg(not(any( - target_os = "redox", - target_os = "fuchsia", - target_os = "haiku" -)))] -mod test_termios; -mod test_uio; -mod test_wait; - -#[cfg(any(target_os = "android", target_os = "linux"))] -mod test_epoll; -#[cfg(target_os = "linux")] -mod test_inotify; -mod test_pthread; -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" -))] -mod test_ptrace; -#[cfg(any(target_os = "android", target_os = "linux"))] -mod test_timerfd; diff --git a/vendor/nix/test/sys/test_aio.rs b/vendor/nix/test/sys/test_aio.rs deleted file mode 100644 index 84086f80c..000000000 --- a/vendor/nix/test/sys/test_aio.rs +++ /dev/null @@ -1,626 +0,0 @@ -use std::{ - io::{Read, Seek, Write}, - ops::Deref, - os::unix::io::AsRawFd, - pin::Pin, - sync::atomic::{AtomicBool, Ordering}, - thread, time, -}; - -use libc::c_int; -use nix::{ - errno::*, - sys::{ - aio::*, - signal::{ - sigaction, SaFlags, SigAction, SigHandler, SigSet, SigevNotify, - Signal, - }, - time::{TimeSpec, TimeValLike}, - }, -}; -use tempfile::tempfile; - -lazy_static! { - pub static ref SIGNALED: AtomicBool = AtomicBool::new(false); -} - -extern "C" fn sigfunc(_: c_int) { - SIGNALED.store(true, Ordering::Relaxed); -} - -// Helper that polls an AioCb for completion or error -macro_rules! poll_aio { - ($aiocb: expr) => { - loop { - let err = $aiocb.as_mut().error(); - if err != Err(Errno::EINPROGRESS) { - break err; - }; - thread::sleep(time::Duration::from_millis(10)); - } - }; -} - -mod aio_fsync { - use super::*; - - #[test] - fn test_accessors() { - let aiocb = AioFsync::new( - 1001, - AioFsyncMode::O_SYNC, - 42, - SigevNotify::SigevSignal { - signal: Signal::SIGUSR2, - si_value: 99, - }, - ); - assert_eq!(1001, aiocb.fd()); - assert_eq!(AioFsyncMode::O_SYNC, aiocb.mode()); - assert_eq!(42, aiocb.priority()); - let sev = aiocb.sigevent().sigevent(); - assert_eq!(Signal::SIGUSR2 as i32, sev.sigev_signo); - assert_eq!(99, sev.sigev_value.sival_ptr as i64); - } - - /// `AioFsync::submit` should not modify the `AioCb` object if - /// `libc::aio_fsync` returns an error - // Skip on Linux, because Linux's AIO implementation can't detect errors - // synchronously - #[test] - #[cfg(any(target_os = "freebsd", target_os = "macos"))] - fn error() { - use std::mem; - - const INITIAL: &[u8] = b"abcdef123456"; - // Create an invalid AioFsyncMode - let mode = unsafe { mem::transmute(666) }; - let mut f = tempfile().unwrap(); - f.write_all(INITIAL).unwrap(); - let mut aiof = Box::pin(AioFsync::new( - f.as_raw_fd(), - mode, - 0, - SigevNotify::SigevNone, - )); - let err = aiof.as_mut().submit(); - err.expect_err("assertion failed"); - } - - #[test] - #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] - fn ok() { - const INITIAL: &[u8] = b"abcdef123456"; - let mut f = tempfile().unwrap(); - f.write_all(INITIAL).unwrap(); - let fd = f.as_raw_fd(); - let mut aiof = Box::pin(AioFsync::new( - fd, - AioFsyncMode::O_SYNC, - 0, - SigevNotify::SigevNone, - )); - aiof.as_mut().submit().unwrap(); - poll_aio!(&mut aiof).unwrap(); - aiof.as_mut().aio_return().unwrap(); - } -} - -mod aio_read { - use super::*; - - #[test] - fn test_accessors() { - let mut rbuf = vec![0; 4]; - let aiocb = AioRead::new( - 1001, - 2, //offset - &mut rbuf, - 42, //priority - SigevNotify::SigevSignal { - signal: Signal::SIGUSR2, - si_value: 99, - }, - ); - assert_eq!(1001, aiocb.fd()); - assert_eq!(4, aiocb.nbytes()); - assert_eq!(2, aiocb.offset()); - assert_eq!(42, aiocb.priority()); - let sev = aiocb.sigevent().sigevent(); - assert_eq!(Signal::SIGUSR2 as i32, sev.sigev_signo); - assert_eq!(99, sev.sigev_value.sival_ptr as i64); - } - - // Tests AioWrite.cancel. We aren't trying to test the OS's implementation, - // only our bindings. So it's sufficient to check that cancel - // returned any AioCancelStat value. - #[test] - #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] - fn cancel() { - const INITIAL: &[u8] = b"abcdef123456"; - let mut rbuf = vec![0; 4]; - let mut f = tempfile().unwrap(); - f.write_all(INITIAL).unwrap(); - let fd = f.as_raw_fd(); - let mut aior = - Box::pin(AioRead::new(fd, 2, &mut rbuf, 0, SigevNotify::SigevNone)); - aior.as_mut().submit().unwrap(); - - aior.as_mut().cancel().unwrap(); - - // Wait for aiow to complete, but don't care whether it succeeded - let _ = poll_aio!(&mut aior); - let _ = aior.as_mut().aio_return(); - } - - /// `AioRead::submit` should not modify the `AioCb` object if - /// `libc::aio_read` returns an error - // Skip on Linux, because Linux's AIO implementation can't detect errors - // synchronously - #[test] - #[cfg(any(target_os = "freebsd", target_os = "macos"))] - fn error() { - const INITIAL: &[u8] = b"abcdef123456"; - let mut rbuf = vec![0; 4]; - let mut f = tempfile().unwrap(); - f.write_all(INITIAL).unwrap(); - let mut aior = Box::pin(AioRead::new( - f.as_raw_fd(), - -1, //an invalid offset - &mut rbuf, - 0, //priority - SigevNotify::SigevNone, - )); - aior.as_mut().submit().expect_err("assertion failed"); - } - - // Test a simple aio operation with no completion notification. We must - // poll for completion - #[test] - #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] - fn ok() { - const INITIAL: &[u8] = b"abcdef123456"; - let mut rbuf = vec![0; 4]; - const EXPECT: &[u8] = b"cdef"; - let mut f = tempfile().unwrap(); - f.write_all(INITIAL).unwrap(); - { - let fd = f.as_raw_fd(); - let mut aior = Box::pin(AioRead::new( - fd, - 2, - &mut rbuf, - 0, - SigevNotify::SigevNone, - )); - aior.as_mut().submit().unwrap(); - - let err = poll_aio!(&mut aior); - assert_eq!(err, Ok(())); - assert_eq!(aior.as_mut().aio_return().unwrap(), EXPECT.len()); - } - assert_eq!(EXPECT, rbuf.deref().deref()); - } - - // Like ok, but allocates the structure on the stack. - #[test] - #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] - fn on_stack() { - const INITIAL: &[u8] = b"abcdef123456"; - let mut rbuf = vec![0; 4]; - const EXPECT: &[u8] = b"cdef"; - let mut f = tempfile().unwrap(); - f.write_all(INITIAL).unwrap(); - { - let fd = f.as_raw_fd(); - let mut aior = - AioRead::new(fd, 2, &mut rbuf, 0, SigevNotify::SigevNone); - let mut aior = unsafe { Pin::new_unchecked(&mut aior) }; - aior.as_mut().submit().unwrap(); - - let err = poll_aio!(&mut aior); - assert_eq!(err, Ok(())); - assert_eq!(aior.as_mut().aio_return().unwrap(), EXPECT.len()); - } - assert_eq!(EXPECT, rbuf.deref().deref()); - } -} - -#[cfg(target_os = "freebsd")] -#[cfg(fbsd14)] -mod aio_readv { - use std::io::IoSliceMut; - - use super::*; - - #[test] - fn test_accessors() { - let mut rbuf0 = vec![0; 4]; - let mut rbuf1 = vec![0; 8]; - let mut rbufs = - [IoSliceMut::new(&mut rbuf0), IoSliceMut::new(&mut rbuf1)]; - let aiocb = AioReadv::new( - 1001, - 2, //offset - &mut rbufs, - 42, //priority - SigevNotify::SigevSignal { - signal: Signal::SIGUSR2, - si_value: 99, - }, - ); - assert_eq!(1001, aiocb.fd()); - assert_eq!(2, aiocb.iovlen()); - assert_eq!(2, aiocb.offset()); - assert_eq!(42, aiocb.priority()); - let sev = aiocb.sigevent().sigevent(); - assert_eq!(Signal::SIGUSR2 as i32, sev.sigev_signo); - assert_eq!(99, sev.sigev_value.sival_ptr as i64); - } - - #[test] - #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] - fn ok() { - const INITIAL: &[u8] = b"abcdef123456"; - let mut rbuf0 = vec![0; 4]; - let mut rbuf1 = vec![0; 2]; - let mut rbufs = - [IoSliceMut::new(&mut rbuf0), IoSliceMut::new(&mut rbuf1)]; - const EXPECT0: &[u8] = b"cdef"; - const EXPECT1: &[u8] = b"12"; - let mut f = tempfile().unwrap(); - f.write_all(INITIAL).unwrap(); - { - let fd = f.as_raw_fd(); - let mut aior = Box::pin(AioReadv::new( - fd, - 2, - &mut rbufs, - 0, - SigevNotify::SigevNone, - )); - aior.as_mut().submit().unwrap(); - - let err = poll_aio!(&mut aior); - assert_eq!(err, Ok(())); - assert_eq!( - aior.as_mut().aio_return().unwrap(), - EXPECT0.len() + EXPECT1.len() - ); - } - assert_eq!(&EXPECT0, &rbuf0); - assert_eq!(&EXPECT1, &rbuf1); - } -} - -mod aio_write { - use super::*; - - #[test] - fn test_accessors() { - let wbuf = vec![0; 4]; - let aiocb = AioWrite::new( - 1001, - 2, //offset - &wbuf, - 42, //priority - SigevNotify::SigevSignal { - signal: Signal::SIGUSR2, - si_value: 99, - }, - ); - assert_eq!(1001, aiocb.fd()); - assert_eq!(4, aiocb.nbytes()); - assert_eq!(2, aiocb.offset()); - assert_eq!(42, aiocb.priority()); - let sev = aiocb.sigevent().sigevent(); - assert_eq!(Signal::SIGUSR2 as i32, sev.sigev_signo); - assert_eq!(99, sev.sigev_value.sival_ptr as i64); - } - - // Tests AioWrite.cancel. We aren't trying to test the OS's implementation, - // only our bindings. So it's sufficient to check that cancel - // returned any AioCancelStat value. - #[test] - #[cfg_attr(target_env = "musl", ignore)] - fn cancel() { - let wbuf: &[u8] = b"CDEF"; - - let f = tempfile().unwrap(); - let mut aiow = Box::pin(AioWrite::new( - f.as_raw_fd(), - 0, - wbuf, - 0, - SigevNotify::SigevNone, - )); - aiow.as_mut().submit().unwrap(); - let err = aiow.as_mut().error(); - assert!(err == Ok(()) || err == Err(Errno::EINPROGRESS)); - - aiow.as_mut().cancel().unwrap(); - - // Wait for aiow to complete, but don't care whether it succeeded - let _ = poll_aio!(&mut aiow); - let _ = aiow.as_mut().aio_return(); - } - - // Test a simple aio operation with no completion notification. We must - // poll for completion. - #[test] - #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] - fn ok() { - const INITIAL: &[u8] = b"abcdef123456"; - let wbuf = "CDEF".to_string().into_bytes(); - let mut rbuf = Vec::new(); - const EXPECT: &[u8] = b"abCDEF123456"; - - let mut f = tempfile().unwrap(); - f.write_all(INITIAL).unwrap(); - let mut aiow = Box::pin(AioWrite::new( - f.as_raw_fd(), - 2, - &wbuf, - 0, - SigevNotify::SigevNone, - )); - aiow.as_mut().submit().unwrap(); - - let err = poll_aio!(&mut aiow); - assert_eq!(err, Ok(())); - assert_eq!(aiow.as_mut().aio_return().unwrap(), wbuf.len()); - - f.rewind().unwrap(); - let len = f.read_to_end(&mut rbuf).unwrap(); - assert_eq!(len, EXPECT.len()); - assert_eq!(rbuf, EXPECT); - } - - // Like ok, but allocates the structure on the stack. - #[test] - #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] - fn on_stack() { - const INITIAL: &[u8] = b"abcdef123456"; - let wbuf = "CDEF".to_string().into_bytes(); - let mut rbuf = Vec::new(); - const EXPECT: &[u8] = b"abCDEF123456"; - - let mut f = tempfile().unwrap(); - f.write_all(INITIAL).unwrap(); - let mut aiow = AioWrite::new( - f.as_raw_fd(), - 2, //offset - &wbuf, - 0, //priority - SigevNotify::SigevNone, - ); - let mut aiow = unsafe { Pin::new_unchecked(&mut aiow) }; - aiow.as_mut().submit().unwrap(); - - let err = poll_aio!(&mut aiow); - assert_eq!(err, Ok(())); - assert_eq!(aiow.as_mut().aio_return().unwrap(), wbuf.len()); - - f.rewind().unwrap(); - let len = f.read_to_end(&mut rbuf).unwrap(); - assert_eq!(len, EXPECT.len()); - assert_eq!(rbuf, EXPECT); - } - - /// `AioWrite::write` should not modify the `AioCb` object if - /// `libc::aio_write` returns an error. - // Skip on Linux, because Linux's AIO implementation can't detect errors - // synchronously - #[test] - #[cfg(any(target_os = "freebsd", target_os = "macos"))] - fn error() { - let wbuf = "CDEF".to_string().into_bytes(); - let mut aiow = Box::pin(AioWrite::new( - 666, // An invalid file descriptor - 0, //offset - &wbuf, - 0, //priority - SigevNotify::SigevNone, - )); - aiow.as_mut().submit().expect_err("assertion failed"); - // Dropping the AioWrite at this point should not panic - } -} - -#[cfg(target_os = "freebsd")] -#[cfg(fbsd14)] -mod aio_writev { - use std::io::IoSlice; - - use super::*; - - #[test] - fn test_accessors() { - let wbuf0 = vec![0; 4]; - let wbuf1 = vec![0; 8]; - let wbufs = [IoSlice::new(&wbuf0), IoSlice::new(&wbuf1)]; - let aiocb = AioWritev::new( - 1001, - 2, //offset - &wbufs, - 42, //priority - SigevNotify::SigevSignal { - signal: Signal::SIGUSR2, - si_value: 99, - }, - ); - assert_eq!(1001, aiocb.fd()); - assert_eq!(2, aiocb.iovlen()); - assert_eq!(2, aiocb.offset()); - assert_eq!(42, aiocb.priority()); - let sev = aiocb.sigevent().sigevent(); - assert_eq!(Signal::SIGUSR2 as i32, sev.sigev_signo); - assert_eq!(99, sev.sigev_value.sival_ptr as i64); - } - - // Test a simple aio operation with no completion notification. We must - // poll for completion. - #[test] - #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] - fn ok() { - const INITIAL: &[u8] = b"abcdef123456"; - let wbuf0 = b"BC"; - let wbuf1 = b"DEF"; - let wbufs = [IoSlice::new(wbuf0), IoSlice::new(wbuf1)]; - let wlen = wbuf0.len() + wbuf1.len(); - let mut rbuf = Vec::new(); - const EXPECT: &[u8] = b"aBCDEF123456"; - - let mut f = tempfile().unwrap(); - f.write_all(INITIAL).unwrap(); - let mut aiow = Box::pin(AioWritev::new( - f.as_raw_fd(), - 1, - &wbufs, - 0, - SigevNotify::SigevNone, - )); - aiow.as_mut().submit().unwrap(); - - let err = poll_aio!(&mut aiow); - assert_eq!(err, Ok(())); - assert_eq!(aiow.as_mut().aio_return().unwrap(), wlen); - - f.rewind().unwrap(); - let len = f.read_to_end(&mut rbuf).unwrap(); - assert_eq!(len, EXPECT.len()); - assert_eq!(rbuf, EXPECT); - } -} - -// Test an aio operation with completion delivered by a signal -#[test] -#[cfg_attr( - any( - all(target_env = "musl", target_arch = "x86_64"), - target_arch = "mips", - target_arch = "mips64" - ), - ignore -)] -fn sigev_signal() { - let _m = crate::SIGNAL_MTX.lock(); - let sa = SigAction::new( - SigHandler::Handler(sigfunc), - SaFlags::SA_RESETHAND, - SigSet::empty(), - ); - SIGNALED.store(false, Ordering::Relaxed); - unsafe { sigaction(Signal::SIGUSR2, &sa) }.unwrap(); - - const INITIAL: &[u8] = b"abcdef123456"; - const WBUF: &[u8] = b"CDEF"; - let mut rbuf = Vec::new(); - const EXPECT: &[u8] = b"abCDEF123456"; - - let mut f = tempfile().unwrap(); - f.write_all(INITIAL).unwrap(); - let mut aiow = Box::pin(AioWrite::new( - f.as_raw_fd(), - 2, //offset - WBUF, - 0, //priority - SigevNotify::SigevSignal { - signal: Signal::SIGUSR2, - si_value: 0, //TODO: validate in sigfunc - }, - )); - aiow.as_mut().submit().unwrap(); - while !SIGNALED.load(Ordering::Relaxed) { - thread::sleep(time::Duration::from_millis(10)); - } - - assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len()); - f.rewind().unwrap(); - let len = f.read_to_end(&mut rbuf).unwrap(); - assert_eq!(len, EXPECT.len()); - assert_eq!(rbuf, EXPECT); -} - -// Tests using aio_cancel_all for all outstanding IOs. -#[test] -#[cfg_attr(target_env = "musl", ignore)] -fn test_aio_cancel_all() { - let wbuf: &[u8] = b"CDEF"; - - let f = tempfile().unwrap(); - let mut aiocb = Box::pin(AioWrite::new( - f.as_raw_fd(), - 0, //offset - wbuf, - 0, //priority - SigevNotify::SigevNone, - )); - aiocb.as_mut().submit().unwrap(); - let err = aiocb.as_mut().error(); - assert!(err == Ok(()) || err == Err(Errno::EINPROGRESS)); - - aio_cancel_all(f.as_raw_fd()).unwrap(); - - // Wait for aiocb to complete, but don't care whether it succeeded - let _ = poll_aio!(&mut aiocb); - let _ = aiocb.as_mut().aio_return(); -} - -#[test] -// On Cirrus on Linux, this test fails due to a glibc bug. -// https://github.com/nix-rust/nix/issues/1099 -#[cfg_attr(target_os = "linux", ignore)] -// On Cirrus, aio_suspend is failing with EINVAL -// https://github.com/nix-rust/nix/issues/1361 -#[cfg_attr(target_os = "macos", ignore)] -fn test_aio_suspend() { - const INITIAL: &[u8] = b"abcdef123456"; - const WBUF: &[u8] = b"CDEFG"; - let timeout = TimeSpec::seconds(10); - let mut rbuf = vec![0; 4]; - let rlen = rbuf.len(); - let mut f = tempfile().unwrap(); - f.write_all(INITIAL).unwrap(); - - let mut wcb = Box::pin(AioWrite::new( - f.as_raw_fd(), - 2, //offset - WBUF, - 0, //priority - SigevNotify::SigevNone, - )); - - let mut rcb = Box::pin(AioRead::new( - f.as_raw_fd(), - 8, //offset - &mut rbuf, - 0, //priority - SigevNotify::SigevNone, - )); - wcb.as_mut().submit().unwrap(); - rcb.as_mut().submit().unwrap(); - loop { - { - let cbbuf = [ - &*wcb as &dyn AsRef<libc::aiocb>, - &*rcb as &dyn AsRef<libc::aiocb>, - ]; - let r = aio_suspend(&cbbuf[..], Some(timeout)); - match r { - Err(Errno::EINTR) => continue, - Err(e) => panic!("aio_suspend returned {:?}", e), - Ok(_) => (), - }; - } - if rcb.as_mut().error() != Err(Errno::EINPROGRESS) - && wcb.as_mut().error() != Err(Errno::EINPROGRESS) - { - break; - } - } - - assert_eq!(wcb.as_mut().aio_return().unwrap(), WBUF.len()); - assert_eq!(rcb.as_mut().aio_return().unwrap(), rlen); -} diff --git a/vendor/nix/test/sys/test_aio_drop.rs b/vendor/nix/test/sys/test_aio_drop.rs deleted file mode 100644 index bbe6623fd..000000000 --- a/vendor/nix/test/sys/test_aio_drop.rs +++ /dev/null @@ -1,35 +0,0 @@ -// Test dropping an AioCb that hasn't yet finished. -// This must happen in its own process, because on OSX this test seems to hose -// the AIO subsystem and causes subsequent tests to fail -#[test] -#[should_panic(expected = "Dropped an in-progress AioCb")] -#[cfg(all( - not(target_env = "musl"), - not(target_env = "uclibc"), - any( - target_os = "linux", - target_os = "ios", - target_os = "macos", - target_os = "freebsd", - target_os = "netbsd" - ) -))] -fn test_drop() { - use nix::sys::aio::*; - use nix::sys::signal::*; - use std::os::unix::io::AsRawFd; - use tempfile::tempfile; - - const WBUF: &[u8] = b"CDEF"; - - let f = tempfile().unwrap(); - f.set_len(6).unwrap(); - let mut aiocb = Box::pin(AioWrite::new( - f.as_raw_fd(), - 2, //offset - WBUF, - 0, //priority - SigevNotify::SigevNone, - )); - aiocb.as_mut().submit().unwrap(); -} diff --git a/vendor/nix/test/sys/test_epoll.rs b/vendor/nix/test/sys/test_epoll.rs deleted file mode 100644 index 915691595..000000000 --- a/vendor/nix/test/sys/test_epoll.rs +++ /dev/null @@ -1,24 +0,0 @@ -use nix::errno::Errno; -use nix::sys::epoll::{epoll_create1, epoll_ctl}; -use nix::sys::epoll::{EpollCreateFlags, EpollEvent, EpollFlags, EpollOp}; - -#[test] -pub fn test_epoll_errno() { - let efd = epoll_create1(EpollCreateFlags::empty()).unwrap(); - let result = epoll_ctl(efd, EpollOp::EpollCtlDel, 1, None); - result.expect_err("assertion failed"); - assert_eq!(result.unwrap_err(), Errno::ENOENT); - - let result = epoll_ctl(efd, EpollOp::EpollCtlAdd, 1, None); - result.expect_err("assertion failed"); - assert_eq!(result.unwrap_err(), Errno::EINVAL); -} - -#[test] -pub fn test_epoll_ctl() { - let efd = epoll_create1(EpollCreateFlags::empty()).unwrap(); - let mut event = - EpollEvent::new(EpollFlags::EPOLLIN | EpollFlags::EPOLLERR, 1); - epoll_ctl(efd, EpollOp::EpollCtlAdd, 1, &mut event).unwrap(); - epoll_ctl(efd, EpollOp::EpollCtlDel, 1, None).unwrap(); -} diff --git a/vendor/nix/test/sys/test_inotify.rs b/vendor/nix/test/sys/test_inotify.rs deleted file mode 100644 index bb5851a90..000000000 --- a/vendor/nix/test/sys/test_inotify.rs +++ /dev/null @@ -1,65 +0,0 @@ -use nix::errno::Errno; -use nix::sys::inotify::{AddWatchFlags, InitFlags, Inotify}; -use std::ffi::OsString; -use std::fs::{rename, File}; - -#[test] -pub fn test_inotify() { - let instance = Inotify::init(InitFlags::IN_NONBLOCK).unwrap(); - let tempdir = tempfile::tempdir().unwrap(); - - instance - .add_watch(tempdir.path(), AddWatchFlags::IN_ALL_EVENTS) - .unwrap(); - - let events = instance.read_events(); - assert_eq!(events.unwrap_err(), Errno::EAGAIN); - - File::create(tempdir.path().join("test")).unwrap(); - - let events = instance.read_events().unwrap(); - assert_eq!(events[0].name, Some(OsString::from("test"))); -} - -#[test] -pub fn test_inotify_multi_events() { - let instance = Inotify::init(InitFlags::IN_NONBLOCK).unwrap(); - let tempdir = tempfile::tempdir().unwrap(); - - instance - .add_watch(tempdir.path(), AddWatchFlags::IN_ALL_EVENTS) - .unwrap(); - - let events = instance.read_events(); - assert_eq!(events.unwrap_err(), Errno::EAGAIN); - - File::create(tempdir.path().join("test")).unwrap(); - rename(tempdir.path().join("test"), tempdir.path().join("test2")).unwrap(); - - // Now there should be 5 events in queue: - // - IN_CREATE on test - // - IN_OPEN on test - // - IN_CLOSE_WRITE on test - // - IN_MOVED_FROM on test with a cookie - // - IN_MOVED_TO on test2 with the same cookie - - let events = instance.read_events().unwrap(); - assert_eq!(events.len(), 5); - - assert_eq!(events[0].mask, AddWatchFlags::IN_CREATE); - assert_eq!(events[0].name, Some(OsString::from("test"))); - - assert_eq!(events[1].mask, AddWatchFlags::IN_OPEN); - assert_eq!(events[1].name, Some(OsString::from("test"))); - - assert_eq!(events[2].mask, AddWatchFlags::IN_CLOSE_WRITE); - assert_eq!(events[2].name, Some(OsString::from("test"))); - - assert_eq!(events[3].mask, AddWatchFlags::IN_MOVED_FROM); - assert_eq!(events[3].name, Some(OsString::from("test"))); - - assert_eq!(events[4].mask, AddWatchFlags::IN_MOVED_TO); - assert_eq!(events[4].name, Some(OsString::from("test2"))); - - assert_eq!(events[3].cookie, events[4].cookie); -} diff --git a/vendor/nix/test/sys/test_ioctl.rs b/vendor/nix/test/sys/test_ioctl.rs deleted file mode 100644 index 40f60cfdb..000000000 --- a/vendor/nix/test/sys/test_ioctl.rs +++ /dev/null @@ -1,376 +0,0 @@ -#![allow(dead_code)] - -// Simple tests to ensure macro generated fns compile -ioctl_none_bad!(do_bad, 0x1234); -ioctl_read_bad!(do_bad_read, 0x1234, u16); -ioctl_write_int_bad!(do_bad_write_int, 0x1234); -ioctl_write_ptr_bad!(do_bad_write_ptr, 0x1234, u8); -ioctl_readwrite_bad!(do_bad_readwrite, 0x1234, u32); -ioctl_none!(do_none, 0, 0); -ioctl_read!(read_test, 0, 0, u32); -ioctl_write_int!(write_ptr_int, 0, 0); -ioctl_write_ptr!(write_ptr_u8, 0, 0, u8); -ioctl_write_ptr!(write_ptr_u32, 0, 0, u32); -ioctl_write_ptr!(write_ptr_u64, 0, 0, u64); -ioctl_readwrite!(readwrite_test, 0, 0, u64); -ioctl_read_buf!(readbuf_test, 0, 0, u32); -const SPI_IOC_MAGIC: u8 = b'k'; -const SPI_IOC_MESSAGE: u8 = 0; -ioctl_write_buf!(writebuf_test_consts, SPI_IOC_MAGIC, SPI_IOC_MESSAGE, u8); -ioctl_write_buf!(writebuf_test_u8, 0, 0, u8); -ioctl_write_buf!(writebuf_test_u32, 0, 0, u32); -ioctl_write_buf!(writebuf_test_u64, 0, 0, u64); -ioctl_readwrite_buf!(readwritebuf_test, 0, 0, u32); - -// See C code for source of values for op calculations (does NOT work for mips/powerpc): -// https://gist.github.com/posborne/83ea6880770a1aef332e -// -// TODO: Need a way to compute these constants at test time. Using precomputed -// values is fragile and needs to be maintained. - -#[cfg(any(target_os = "linux", target_os = "android"))] -mod linux { - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - #[test] - fn test_op_none() { - if cfg!(any( - target_arch = "mips", - target_arch = "mips64", - target_arch = "powerpc", - target_arch = "powerpc64" - )) { - assert_eq!(request_code_none!(b'q', 10) as u32, 0x2000_710A); - assert_eq!(request_code_none!(b'a', 255) as u32, 0x2000_61FF); - } else { - assert_eq!(request_code_none!(b'q', 10) as u32, 0x0000_710A); - assert_eq!(request_code_none!(b'a', 255) as u32, 0x0000_61FF); - } - } - - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - #[test] - fn test_op_write() { - if cfg!(any( - target_arch = "mips", - target_arch = "mips64", - target_arch = "powerpc", - target_arch = "powerpc64" - )) { - assert_eq!(request_code_write!(b'z', 10, 1) as u32, 0x8001_7A0A); - assert_eq!(request_code_write!(b'z', 10, 512) as u32, 0x8200_7A0A); - } else { - assert_eq!(request_code_write!(b'z', 10, 1) as u32, 0x4001_7A0A); - assert_eq!(request_code_write!(b'z', 10, 512) as u32, 0x4200_7A0A); - } - } - - #[cfg(target_pointer_width = "64")] - #[test] - fn test_op_write_64() { - if cfg!(any(target_arch = "mips64", target_arch = "powerpc64")) { - assert_eq!( - request_code_write!(b'z', 10, 1u64 << 32) as u32, - 0x8000_7A0A - ); - } else { - assert_eq!( - request_code_write!(b'z', 10, 1u64 << 32) as u32, - 0x4000_7A0A - ); - } - } - - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - #[test] - fn test_op_read() { - if cfg!(any( - target_arch = "mips", - target_arch = "mips64", - target_arch = "powerpc", - target_arch = "powerpc64" - )) { - assert_eq!(request_code_read!(b'z', 10, 1) as u32, 0x4001_7A0A); - assert_eq!(request_code_read!(b'z', 10, 512) as u32, 0x4200_7A0A); - } else { - assert_eq!(request_code_read!(b'z', 10, 1) as u32, 0x8001_7A0A); - assert_eq!(request_code_read!(b'z', 10, 512) as u32, 0x8200_7A0A); - } - } - - #[cfg(target_pointer_width = "64")] - #[test] - fn test_op_read_64() { - if cfg!(any(target_arch = "mips64", target_arch = "powerpc64")) { - assert_eq!( - request_code_read!(b'z', 10, 1u64 << 32) as u32, - 0x4000_7A0A - ); - } else { - assert_eq!( - request_code_read!(b'z', 10, 1u64 << 32) as u32, - 0x8000_7A0A - ); - } - } - - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] - #[test] - fn test_op_read_write() { - assert_eq!(request_code_readwrite!(b'z', 10, 1) as u32, 0xC001_7A0A); - assert_eq!(request_code_readwrite!(b'z', 10, 512) as u32, 0xC200_7A0A); - } - - #[cfg(target_pointer_width = "64")] - #[test] - fn test_op_read_write_64() { - assert_eq!( - request_code_readwrite!(b'z', 10, 1u64 << 32) as u32, - 0xC000_7A0A - ); - } -} - -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" -))] -mod bsd { - #[test] - fn test_op_none() { - assert_eq!(request_code_none!(b'q', 10), 0x2000_710A); - assert_eq!(request_code_none!(b'a', 255), 0x2000_61FF); - } - - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[test] - fn test_op_write_int() { - assert_eq!(request_code_write_int!(b'v', 4), 0x2004_7604); - assert_eq!(request_code_write_int!(b'p', 2), 0x2004_7002); - } - - #[test] - fn test_op_write() { - assert_eq!(request_code_write!(b'z', 10, 1), 0x8001_7A0A); - assert_eq!(request_code_write!(b'z', 10, 512), 0x8200_7A0A); - } - - #[cfg(target_pointer_width = "64")] - #[test] - fn test_op_write_64() { - assert_eq!(request_code_write!(b'z', 10, 1u64 << 32), 0x8000_7A0A); - } - - #[test] - fn test_op_read() { - assert_eq!(request_code_read!(b'z', 10, 1), 0x4001_7A0A); - assert_eq!(request_code_read!(b'z', 10, 512), 0x4200_7A0A); - } - - #[cfg(target_pointer_width = "64")] - #[test] - fn test_op_read_64() { - assert_eq!(request_code_read!(b'z', 10, 1u64 << 32), 0x4000_7A0A); - } - - #[test] - fn test_op_read_write() { - assert_eq!(request_code_readwrite!(b'z', 10, 1), 0xC001_7A0A); - assert_eq!(request_code_readwrite!(b'z', 10, 512), 0xC200_7A0A); - } - - #[cfg(target_pointer_width = "64")] - #[test] - fn test_op_read_write_64() { - assert_eq!(request_code_readwrite!(b'z', 10, 1u64 << 32), 0xC000_7A0A); - } -} - -#[cfg(any(target_os = "android", target_os = "linux"))] -mod linux_ioctls { - use std::mem; - use std::os::unix::io::AsRawFd; - - use libc::{termios, TCGETS, TCSBRK, TCSETS, TIOCNXCL}; - use tempfile::tempfile; - - use nix::errno::Errno; - - ioctl_none_bad!(tiocnxcl, TIOCNXCL); - #[test] - fn test_ioctl_none_bad() { - let file = tempfile().unwrap(); - let res = unsafe { tiocnxcl(file.as_raw_fd()) }; - assert_eq!(res, Err(Errno::ENOTTY)); - } - - ioctl_read_bad!(tcgets, TCGETS, termios); - #[test] - fn test_ioctl_read_bad() { - let file = tempfile().unwrap(); - let mut termios = unsafe { mem::zeroed() }; - let res = unsafe { tcgets(file.as_raw_fd(), &mut termios) }; - assert_eq!(res, Err(Errno::ENOTTY)); - } - - ioctl_write_int_bad!(tcsbrk, TCSBRK); - #[test] - fn test_ioctl_write_int_bad() { - let file = tempfile().unwrap(); - let res = unsafe { tcsbrk(file.as_raw_fd(), 0) }; - assert_eq!(res, Err(Errno::ENOTTY)); - } - - ioctl_write_ptr_bad!(tcsets, TCSETS, termios); - #[test] - fn test_ioctl_write_ptr_bad() { - let file = tempfile().unwrap(); - let termios: termios = unsafe { mem::zeroed() }; - let res = unsafe { tcsets(file.as_raw_fd(), &termios) }; - assert_eq!(res, Err(Errno::ENOTTY)); - } - - // FIXME: Find a suitable example for `ioctl_readwrite_bad` - - // From linux/videodev2.h - ioctl_none!(log_status, b'V', 70); - #[test] - fn test_ioctl_none() { - let file = tempfile().unwrap(); - let res = unsafe { log_status(file.as_raw_fd()) }; - assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS)); - } - - #[repr(C)] - pub struct v4l2_audio { - index: u32, - name: [u8; 32], - capability: u32, - mode: u32, - reserved: [u32; 2], - } - - // From linux/videodev2.h - ioctl_write_ptr!(s_audio, b'V', 34, v4l2_audio); - #[test] - fn test_ioctl_write_ptr() { - let file = tempfile().unwrap(); - let data: v4l2_audio = unsafe { mem::zeroed() }; - let res = unsafe { s_audio(file.as_raw_fd(), &data) }; - assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS)); - } - - // From linux/net/bluetooth/hci_sock.h - const HCI_IOC_MAGIC: u8 = b'H'; - const HCI_IOC_HCIDEVUP: u8 = 201; - ioctl_write_int!(hcidevup, HCI_IOC_MAGIC, HCI_IOC_HCIDEVUP); - #[test] - fn test_ioctl_write_int() { - let file = tempfile().unwrap(); - let res = unsafe { hcidevup(file.as_raw_fd(), 0) }; - assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS)); - } - - // From linux/videodev2.h - ioctl_read!(g_audio, b'V', 33, v4l2_audio); - #[test] - fn test_ioctl_read() { - let file = tempfile().unwrap(); - let mut data: v4l2_audio = unsafe { mem::zeroed() }; - let res = unsafe { g_audio(file.as_raw_fd(), &mut data) }; - assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS)); - } - - // From linux/videodev2.h - ioctl_readwrite!(enum_audio, b'V', 65, v4l2_audio); - #[test] - fn test_ioctl_readwrite() { - let file = tempfile().unwrap(); - let mut data: v4l2_audio = unsafe { mem::zeroed() }; - let res = unsafe { enum_audio(file.as_raw_fd(), &mut data) }; - assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS)); - } - - // FIXME: Find a suitable example for `ioctl_read_buf`. - - #[repr(C)] - pub struct spi_ioc_transfer { - tx_buf: u64, - rx_buf: u64, - len: u32, - speed_hz: u32, - delay_usecs: u16, - bits_per_word: u8, - cs_change: u8, - tx_nbits: u8, - rx_nbits: u8, - pad: u16, - } - - // From linux/spi/spidev.h - ioctl_write_buf!( - spi_ioc_message, - super::SPI_IOC_MAGIC, - super::SPI_IOC_MESSAGE, - spi_ioc_transfer - ); - #[test] - fn test_ioctl_write_buf() { - let file = tempfile().unwrap(); - let data: [spi_ioc_transfer; 4] = unsafe { mem::zeroed() }; - let res = unsafe { spi_ioc_message(file.as_raw_fd(), &data[..]) }; - assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS)); - } - - // FIXME: Find a suitable example for `ioctl_readwrite_buf`. -} - -#[cfg(target_os = "freebsd")] -mod freebsd_ioctls { - use std::mem; - use std::os::unix::io::AsRawFd; - - use libc::termios; - use tempfile::tempfile; - - use nix::errno::Errno; - - // From sys/sys/ttycom.h - const TTY_IOC_MAGIC: u8 = b't'; - const TTY_IOC_TYPE_NXCL: u8 = 14; - const TTY_IOC_TYPE_GETA: u8 = 19; - const TTY_IOC_TYPE_SETA: u8 = 20; - - ioctl_none!(tiocnxcl, TTY_IOC_MAGIC, TTY_IOC_TYPE_NXCL); - #[test] - fn test_ioctl_none() { - let file = tempfile().unwrap(); - let res = unsafe { tiocnxcl(file.as_raw_fd()) }; - assert_eq!(res, Err(Errno::ENOTTY)); - } - - ioctl_read!(tiocgeta, TTY_IOC_MAGIC, TTY_IOC_TYPE_GETA, termios); - #[test] - fn test_ioctl_read() { - let file = tempfile().unwrap(); - let mut termios = unsafe { mem::zeroed() }; - let res = unsafe { tiocgeta(file.as_raw_fd(), &mut termios) }; - assert_eq!(res, Err(Errno::ENOTTY)); - } - - ioctl_write_ptr!(tiocseta, TTY_IOC_MAGIC, TTY_IOC_TYPE_SETA, termios); - #[test] - fn test_ioctl_write_ptr() { - let file = tempfile().unwrap(); - let termios: termios = unsafe { mem::zeroed() }; - let res = unsafe { tiocseta(file.as_raw_fd(), &termios) }; - assert_eq!(res, Err(Errno::ENOTTY)); - } -} diff --git a/vendor/nix/test/sys/test_mman.rs b/vendor/nix/test/sys/test_mman.rs deleted file mode 100644 index e748427bc..000000000 --- a/vendor/nix/test/sys/test_mman.rs +++ /dev/null @@ -1,122 +0,0 @@ -use nix::sys::mman::{mmap, MapFlags, ProtFlags}; -use std::num::NonZeroUsize; - -#[test] -fn test_mmap_anonymous() { - unsafe { - let ptr = mmap( - None, - NonZeroUsize::new(1).unwrap(), - ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, - MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS, - -1, - 0, - ) - .unwrap() as *mut u8; - assert_eq!(*ptr, 0x00u8); - *ptr = 0xffu8; - assert_eq!(*ptr, 0xffu8); - } -} - -#[test] -#[cfg(any(target_os = "linux", target_os = "netbsd"))] -fn test_mremap_grow() { - use nix::libc::{c_void, size_t}; - use nix::sys::mman::{mremap, MRemapFlags}; - - const ONE_K: size_t = 1024; - let one_k_non_zero = NonZeroUsize::new(ONE_K).unwrap(); - - let slice: &mut [u8] = unsafe { - let mem = mmap( - None, - one_k_non_zero, - ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, - MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, - -1, - 0, - ) - .unwrap(); - std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K) - }; - assert_eq!(slice[ONE_K - 1], 0x00); - slice[ONE_K - 1] = 0xFF; - assert_eq!(slice[ONE_K - 1], 0xFF); - - let slice: &mut [u8] = unsafe { - #[cfg(target_os = "linux")] - let mem = mremap( - slice.as_mut_ptr() as *mut c_void, - ONE_K, - 10 * ONE_K, - MRemapFlags::MREMAP_MAYMOVE, - None, - ) - .unwrap(); - #[cfg(target_os = "netbsd")] - let mem = mremap( - slice.as_mut_ptr() as *mut c_void, - ONE_K, - 10 * ONE_K, - MRemapFlags::MAP_REMAPDUP, - None, - ) - .unwrap(); - std::slice::from_raw_parts_mut(mem as *mut u8, 10 * ONE_K) - }; - - // The first KB should still have the old data in it. - assert_eq!(slice[ONE_K - 1], 0xFF); - - // The additional range should be zero-init'd and accessible. - assert_eq!(slice[10 * ONE_K - 1], 0x00); - slice[10 * ONE_K - 1] = 0xFF; - assert_eq!(slice[10 * ONE_K - 1], 0xFF); -} - -#[test] -#[cfg(any(target_os = "linux", target_os = "netbsd"))] -// Segfaults for unknown reasons under QEMU for 32-bit targets -#[cfg_attr(all(target_pointer_width = "32", qemu), ignore)] -fn test_mremap_shrink() { - use nix::libc::{c_void, size_t}; - use nix::sys::mman::{mremap, MRemapFlags}; - use std::num::NonZeroUsize; - - const ONE_K: size_t = 1024; - let ten_one_k = NonZeroUsize::new(10 * ONE_K).unwrap(); - let slice: &mut [u8] = unsafe { - let mem = mmap( - None, - ten_one_k, - ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, - MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, - -1, - 0, - ) - .unwrap(); - std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K) - }; - assert_eq!(slice[ONE_K - 1], 0x00); - slice[ONE_K - 1] = 0xFF; - assert_eq!(slice[ONE_K - 1], 0xFF); - - let slice: &mut [u8] = unsafe { - let mem = mremap( - slice.as_mut_ptr() as *mut c_void, - ten_one_k.into(), - ONE_K, - MRemapFlags::empty(), - None, - ) - .unwrap(); - // Since we didn't supply MREMAP_MAYMOVE, the address should be the - // same. - assert_eq!(mem, slice.as_mut_ptr() as *mut c_void); - std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K) - }; - - // The first KB should still be accessible and have the old data in it. - assert_eq!(slice[ONE_K - 1], 0xFF); -} diff --git a/vendor/nix/test/sys/test_pthread.rs b/vendor/nix/test/sys/test_pthread.rs deleted file mode 100644 index ce048bae6..000000000 --- a/vendor/nix/test/sys/test_pthread.rs +++ /dev/null @@ -1,22 +0,0 @@ -use nix::sys::pthread::*; - -#[cfg(any(target_env = "musl", target_os = "redox"))] -#[test] -fn test_pthread_self() { - let tid = pthread_self(); - assert!(!tid.is_null()); -} - -#[cfg(not(any(target_env = "musl", target_os = "redox")))] -#[test] -fn test_pthread_self() { - let tid = pthread_self(); - assert_ne!(tid, 0); -} - -#[test] -#[cfg(not(target_os = "redox"))] -fn test_pthread_kill_none() { - pthread_kill(pthread_self(), None) - .expect("Should be able to send signal to my thread."); -} diff --git a/vendor/nix/test/sys/test_ptrace.rs b/vendor/nix/test/sys/test_ptrace.rs deleted file mode 100644 index 530560fe1..000000000 --- a/vendor/nix/test/sys/test_ptrace.rs +++ /dev/null @@ -1,275 +0,0 @@ -#[cfg(all( - target_os = "linux", - any(target_arch = "x86_64", target_arch = "x86"), - target_env = "gnu" -))] -use memoffset::offset_of; -use nix::errno::Errno; -use nix::sys::ptrace; -#[cfg(any(target_os = "android", target_os = "linux"))] -use nix::sys::ptrace::Options; -use nix::unistd::getpid; - -#[cfg(any(target_os = "android", target_os = "linux"))] -use std::mem; - -use crate::*; - -#[test] -fn test_ptrace() { - // Just make sure ptrace can be called at all, for now. - // FIXME: qemu-user doesn't implement ptrace on all arches, so permit ENOSYS - require_capability!("test_ptrace", CAP_SYS_PTRACE); - let err = ptrace::attach(getpid()).unwrap_err(); - assert!( - err == Errno::EPERM || err == Errno::EINVAL || err == Errno::ENOSYS - ); -} - -// Just make sure ptrace_setoptions can be called at all, for now. -#[test] -#[cfg(any(target_os = "android", target_os = "linux"))] -fn test_ptrace_setoptions() { - require_capability!("test_ptrace_setoptions", CAP_SYS_PTRACE); - let err = ptrace::setoptions(getpid(), Options::PTRACE_O_TRACESYSGOOD) - .unwrap_err(); - assert_ne!(err, Errno::EOPNOTSUPP); -} - -// Just make sure ptrace_getevent can be called at all, for now. -#[test] -#[cfg(any(target_os = "android", target_os = "linux"))] -fn test_ptrace_getevent() { - require_capability!("test_ptrace_getevent", CAP_SYS_PTRACE); - let err = ptrace::getevent(getpid()).unwrap_err(); - assert_ne!(err, Errno::EOPNOTSUPP); -} - -// Just make sure ptrace_getsiginfo can be called at all, for now. -#[test] -#[cfg(any(target_os = "android", target_os = "linux"))] -fn test_ptrace_getsiginfo() { - require_capability!("test_ptrace_getsiginfo", CAP_SYS_PTRACE); - if let Err(Errno::EOPNOTSUPP) = ptrace::getsiginfo(getpid()) { - panic!("ptrace_getsiginfo returns Errno::EOPNOTSUPP!"); - } -} - -// Just make sure ptrace_setsiginfo can be called at all, for now. -#[test] -#[cfg(any(target_os = "android", target_os = "linux"))] -fn test_ptrace_setsiginfo() { - require_capability!("test_ptrace_setsiginfo", CAP_SYS_PTRACE); - let siginfo = unsafe { mem::zeroed() }; - if let Err(Errno::EOPNOTSUPP) = ptrace::setsiginfo(getpid(), &siginfo) { - panic!("ptrace_setsiginfo returns Errno::EOPNOTSUPP!"); - } -} - -#[test] -fn test_ptrace_cont() { - use nix::sys::ptrace; - use nix::sys::signal::{raise, Signal}; - use nix::sys::wait::{waitpid, WaitPidFlag, WaitStatus}; - use nix::unistd::fork; - use nix::unistd::ForkResult::*; - - require_capability!("test_ptrace_cont", CAP_SYS_PTRACE); - - let _m = crate::FORK_MTX.lock(); - - // FIXME: qemu-user doesn't implement ptrace on all architectures - // and returns ENOSYS in this case. - // We (ab)use this behavior to detect the affected platforms - // and skip the test then. - // On valid platforms the ptrace call should return Errno::EPERM, this - // is already tested by `test_ptrace`. - let err = ptrace::attach(getpid()).unwrap_err(); - if err == Errno::ENOSYS { - return; - } - - match unsafe { fork() }.expect("Error: Fork Failed") { - Child => { - ptrace::traceme().unwrap(); - // As recommended by ptrace(2), raise SIGTRAP to pause the child - // until the parent is ready to continue - loop { - raise(Signal::SIGTRAP).unwrap(); - } - } - Parent { child } => { - assert_eq!( - waitpid(child, None), - Ok(WaitStatus::Stopped(child, Signal::SIGTRAP)) - ); - ptrace::cont(child, None).unwrap(); - assert_eq!( - waitpid(child, None), - Ok(WaitStatus::Stopped(child, Signal::SIGTRAP)) - ); - ptrace::cont(child, Some(Signal::SIGKILL)).unwrap(); - match waitpid(child, None) { - Ok(WaitStatus::Signaled(pid, Signal::SIGKILL, _)) - if pid == child => - { - // FIXME It's been observed on some systems (apple) the - // tracee may not be killed but remain as a zombie process - // affecting other wait based tests. Add an extra kill just - // to make sure there are no zombies. - let _ = waitpid(child, Some(WaitPidFlag::WNOHANG)); - while ptrace::cont(child, Some(Signal::SIGKILL)).is_ok() { - let _ = waitpid(child, Some(WaitPidFlag::WNOHANG)); - } - } - _ => panic!("The process should have been killed"), - } - } - } -} - -#[cfg(target_os = "linux")] -#[test] -fn test_ptrace_interrupt() { - use nix::sys::ptrace; - use nix::sys::signal::Signal; - use nix::sys::wait::{waitpid, WaitPidFlag, WaitStatus}; - use nix::unistd::fork; - use nix::unistd::ForkResult::*; - use std::thread::sleep; - use std::time::Duration; - - require_capability!("test_ptrace_interrupt", CAP_SYS_PTRACE); - - let _m = crate::FORK_MTX.lock(); - - match unsafe { fork() }.expect("Error: Fork Failed") { - Child => loop { - sleep(Duration::from_millis(1000)); - }, - Parent { child } => { - ptrace::seize(child, ptrace::Options::PTRACE_O_TRACESYSGOOD) - .unwrap(); - ptrace::interrupt(child).unwrap(); - assert_eq!( - waitpid(child, None), - Ok(WaitStatus::PtraceEvent(child, Signal::SIGTRAP, 128)) - ); - ptrace::syscall(child, None).unwrap(); - assert_eq!( - waitpid(child, None), - Ok(WaitStatus::PtraceSyscall(child)) - ); - ptrace::detach(child, Some(Signal::SIGKILL)).unwrap(); - match waitpid(child, None) { - Ok(WaitStatus::Signaled(pid, Signal::SIGKILL, _)) - if pid == child => - { - let _ = waitpid(child, Some(WaitPidFlag::WNOHANG)); - while ptrace::cont(child, Some(Signal::SIGKILL)).is_ok() { - let _ = waitpid(child, Some(WaitPidFlag::WNOHANG)); - } - } - _ => panic!("The process should have been killed"), - } - } - } -} - -// ptrace::{setoptions, getregs} are only available in these platforms -#[cfg(all( - target_os = "linux", - any(target_arch = "x86_64", target_arch = "x86"), - target_env = "gnu" -))] -#[test] -fn test_ptrace_syscall() { - use nix::sys::ptrace; - use nix::sys::signal::kill; - use nix::sys::signal::Signal; - use nix::sys::wait::{waitpid, WaitStatus}; - use nix::unistd::fork; - use nix::unistd::getpid; - use nix::unistd::ForkResult::*; - - require_capability!("test_ptrace_syscall", CAP_SYS_PTRACE); - - let _m = crate::FORK_MTX.lock(); - - match unsafe { fork() }.expect("Error: Fork Failed") { - Child => { - ptrace::traceme().unwrap(); - // first sigstop until parent is ready to continue - let pid = getpid(); - kill(pid, Signal::SIGSTOP).unwrap(); - kill(pid, Signal::SIGTERM).unwrap(); - unsafe { - ::libc::_exit(0); - } - } - - Parent { child } => { - assert_eq!( - waitpid(child, None), - Ok(WaitStatus::Stopped(child, Signal::SIGSTOP)) - ); - - // set this option to recognize syscall-stops - ptrace::setoptions(child, ptrace::Options::PTRACE_O_TRACESYSGOOD) - .unwrap(); - - #[cfg(target_arch = "x86_64")] - let get_syscall_id = - || ptrace::getregs(child).unwrap().orig_rax as libc::c_long; - - #[cfg(target_arch = "x86")] - let get_syscall_id = - || ptrace::getregs(child).unwrap().orig_eax as libc::c_long; - - // this duplicates `get_syscall_id` for the purpose of testing `ptrace::read_user`. - #[cfg(target_arch = "x86_64")] - let rax_offset = offset_of!(libc::user_regs_struct, orig_rax); - #[cfg(target_arch = "x86")] - let rax_offset = offset_of!(libc::user_regs_struct, orig_eax); - - let get_syscall_from_user_area = || { - // Find the offset of `user.regs.rax` (or `user.regs.eax` for x86) - let rax_offset = offset_of!(libc::user, regs) + rax_offset; - ptrace::read_user(child, rax_offset as _).unwrap() - as libc::c_long - }; - - // kill entry - ptrace::syscall(child, None).unwrap(); - assert_eq!( - waitpid(child, None), - Ok(WaitStatus::PtraceSyscall(child)) - ); - assert_eq!(get_syscall_id(), ::libc::SYS_kill); - assert_eq!(get_syscall_from_user_area(), ::libc::SYS_kill); - - // kill exit - ptrace::syscall(child, None).unwrap(); - assert_eq!( - waitpid(child, None), - Ok(WaitStatus::PtraceSyscall(child)) - ); - assert_eq!(get_syscall_id(), ::libc::SYS_kill); - assert_eq!(get_syscall_from_user_area(), ::libc::SYS_kill); - - // receive signal - ptrace::syscall(child, None).unwrap(); - assert_eq!( - waitpid(child, None), - Ok(WaitStatus::Stopped(child, Signal::SIGTERM)) - ); - - // inject signal - ptrace::syscall(child, Signal::SIGTERM).unwrap(); - assert_eq!( - waitpid(child, None), - Ok(WaitStatus::Signaled(child, Signal::SIGTERM, false)) - ); - } - } -} diff --git a/vendor/nix/test/sys/test_select.rs b/vendor/nix/test/sys/test_select.rs deleted file mode 100644 index 40bda4d90..000000000 --- a/vendor/nix/test/sys/test_select.rs +++ /dev/null @@ -1,81 +0,0 @@ -use nix::sys::select::*; -use nix::sys::signal::SigSet; -use nix::sys::time::{TimeSpec, TimeValLike}; -use nix::unistd::{pipe, write}; - -#[test] -pub fn test_pselect() { - let _mtx = crate::SIGNAL_MTX.lock(); - - let (r1, w1) = pipe().unwrap(); - write(w1, b"hi!").unwrap(); - let (r2, _w2) = pipe().unwrap(); - - let mut fd_set = FdSet::new(); - fd_set.insert(r1); - fd_set.insert(r2); - - let timeout = TimeSpec::seconds(10); - let sigmask = SigSet::empty(); - assert_eq!( - 1, - pselect(None, &mut fd_set, None, None, &timeout, &sigmask).unwrap() - ); - assert!(fd_set.contains(r1)); - assert!(!fd_set.contains(r2)); -} - -#[test] -pub fn test_pselect_nfds2() { - let (r1, w1) = pipe().unwrap(); - write(w1, b"hi!").unwrap(); - let (r2, _w2) = pipe().unwrap(); - - let mut fd_set = FdSet::new(); - fd_set.insert(r1); - fd_set.insert(r2); - - let timeout = TimeSpec::seconds(10); - assert_eq!( - 1, - pselect( - ::std::cmp::max(r1, r2) + 1, - &mut fd_set, - None, - None, - &timeout, - None - ) - .unwrap() - ); - assert!(fd_set.contains(r1)); - assert!(!fd_set.contains(r2)); -} - -macro_rules! generate_fdset_bad_fd_tests { - ($fd:expr, $($method:ident),* $(,)?) => { - $( - #[test] - #[should_panic] - fn $method() { - FdSet::new().$method($fd); - } - )* - } -} - -mod test_fdset_negative_fd { - use super::*; - generate_fdset_bad_fd_tests!(-1, insert, remove, contains); -} - -mod test_fdset_too_large_fd { - use super::*; - use std::convert::TryInto; - generate_fdset_bad_fd_tests!( - FD_SETSIZE.try_into().unwrap(), - insert, - remove, - contains, - ); -} diff --git a/vendor/nix/test/sys/test_signal.rs b/vendor/nix/test/sys/test_signal.rs deleted file mode 100644 index 3ad14f40c..000000000 --- a/vendor/nix/test/sys/test_signal.rs +++ /dev/null @@ -1,147 +0,0 @@ -#[cfg(not(target_os = "redox"))] -use nix::errno::Errno; -use nix::sys::signal::*; -use nix::unistd::*; -use std::convert::TryFrom; -use std::sync::atomic::{AtomicBool, Ordering}; - -#[test] -fn test_kill_none() { - kill(getpid(), None).expect("Should be able to send signal to myself."); -} - -#[test] -#[cfg(not(target_os = "fuchsia"))] -fn test_killpg_none() { - killpg(getpgrp(), None) - .expect("Should be able to send signal to my process group."); -} - -#[test] -fn test_old_sigaction_flags() { - let _m = crate::SIGNAL_MTX.lock(); - - extern "C" fn handler(_: ::libc::c_int) {} - let act = SigAction::new( - SigHandler::Handler(handler), - SaFlags::empty(), - SigSet::empty(), - ); - let oact = unsafe { sigaction(SIGINT, &act) }.unwrap(); - let _flags = oact.flags(); - let oact = unsafe { sigaction(SIGINT, &act) }.unwrap(); - let _flags = oact.flags(); -} - -#[test] -fn test_sigprocmask_noop() { - sigprocmask(SigmaskHow::SIG_BLOCK, None, None) - .expect("this should be an effective noop"); -} - -#[test] -fn test_sigprocmask() { - let _m = crate::SIGNAL_MTX.lock(); - - // This needs to be a signal that rust doesn't use in the test harness. - const SIGNAL: Signal = Signal::SIGCHLD; - - let mut old_signal_set = SigSet::empty(); - sigprocmask(SigmaskHow::SIG_BLOCK, None, Some(&mut old_signal_set)) - .expect("expect to be able to retrieve old signals"); - - // Make sure the old set doesn't contain the signal, otherwise the following - // test don't make sense. - assert!( - !old_signal_set.contains(SIGNAL), - "the {:?} signal is already blocked, please change to a \ - different one", - SIGNAL - ); - - // Now block the signal. - let mut signal_set = SigSet::empty(); - signal_set.add(SIGNAL); - sigprocmask(SigmaskHow::SIG_BLOCK, Some(&signal_set), None) - .expect("expect to be able to block signals"); - - // And test it again, to make sure the change was effective. - old_signal_set.clear(); - sigprocmask(SigmaskHow::SIG_BLOCK, None, Some(&mut old_signal_set)) - .expect("expect to be able to retrieve old signals"); - assert!( - old_signal_set.contains(SIGNAL), - "expected the {:?} to be blocked", - SIGNAL - ); - - // Reset the signal. - sigprocmask(SigmaskHow::SIG_UNBLOCK, Some(&signal_set), None) - .expect("expect to be able to block signals"); -} - -lazy_static! { - static ref SIGNALED: AtomicBool = AtomicBool::new(false); -} - -extern "C" fn test_sigaction_handler(signal: libc::c_int) { - let signal = Signal::try_from(signal).unwrap(); - SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed); -} - -#[cfg(not(target_os = "redox"))] -extern "C" fn test_sigaction_action( - _: libc::c_int, - _: *mut libc::siginfo_t, - _: *mut libc::c_void, -) { -} - -#[test] -#[cfg(not(target_os = "redox"))] -fn test_signal_sigaction() { - let _m = crate::SIGNAL_MTX.lock(); - - let action_handler = SigHandler::SigAction(test_sigaction_action); - assert_eq!( - unsafe { signal(Signal::SIGINT, action_handler) }.unwrap_err(), - Errno::ENOTSUP - ); -} - -#[test] -fn test_signal() { - let _m = crate::SIGNAL_MTX.lock(); - - unsafe { signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap(); - raise(Signal::SIGINT).unwrap(); - assert_eq!( - unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), - SigHandler::SigIgn - ); - - let handler = SigHandler::Handler(test_sigaction_handler); - assert_eq!( - unsafe { signal(Signal::SIGINT, handler) }.unwrap(), - SigHandler::SigDfl - ); - raise(Signal::SIGINT).unwrap(); - assert!(SIGNALED.load(Ordering::Relaxed)); - - #[cfg(not(any(target_os = "illumos", target_os = "solaris")))] - assert_eq!( - unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), - handler - ); - - // System V based OSes (e.g. illumos and Solaris) always resets the - // disposition to SIG_DFL prior to calling the signal handler - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - assert_eq!( - unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), - SigHandler::SigDfl - ); - - // Restore default signal handler - unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(); -} diff --git a/vendor/nix/test/sys/test_signalfd.rs b/vendor/nix/test/sys/test_signalfd.rs deleted file mode 100644 index 87153c957..000000000 --- a/vendor/nix/test/sys/test_signalfd.rs +++ /dev/null @@ -1,27 +0,0 @@ -use std::convert::TryFrom; - -#[test] -fn test_signalfd() { - use nix::sys::signal::{self, raise, SigSet, Signal}; - use nix::sys::signalfd::SignalFd; - - // Grab the mutex for altering signals so we don't interfere with other tests. - let _m = crate::SIGNAL_MTX.lock(); - - // Block the SIGUSR1 signal from automatic processing for this thread - let mut mask = SigSet::empty(); - mask.add(signal::SIGUSR1); - mask.thread_block().unwrap(); - - let mut fd = SignalFd::new(&mask).unwrap(); - - // Send a SIGUSR1 signal to the current process. Note that this uses `raise` instead of `kill` - // because `kill` with `getpid` isn't correct during multi-threaded execution like during a - // cargo test session. Instead use `raise` which does the correct thing by default. - raise(signal::SIGUSR1).expect("Error: raise(SIGUSR1) failed"); - - // And now catch that same signal. - let res = fd.read_signal().unwrap().unwrap(); - let signo = Signal::try_from(res.ssi_signo as i32).unwrap(); - assert_eq!(signo, signal::SIGUSR1); -} diff --git a/vendor/nix/test/sys/test_socket.rs b/vendor/nix/test/sys/test_socket.rs deleted file mode 100644 index 5adc77ed6..000000000 --- a/vendor/nix/test/sys/test_socket.rs +++ /dev/null @@ -1,2628 +0,0 @@ -#[cfg(any(target_os = "linux", target_os = "android"))] -use crate::*; -use libc::{c_char, sockaddr_storage}; -#[allow(deprecated)] -use nix::sys::socket::InetAddr; -use nix::sys::socket::{ - getsockname, sockaddr, sockaddr_in6, AddressFamily, UnixAddr, -}; -use std::collections::hash_map::DefaultHasher; -use std::hash::{Hash, Hasher}; -use std::mem::{self, MaybeUninit}; -use std::net::{self, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; -use std::os::unix::io::RawFd; -use std::path::Path; -use std::slice; -use std::str::FromStr; - -#[allow(deprecated)] -#[test] -pub fn test_inetv4_addr_to_sock_addr() { - let actual: net::SocketAddr = FromStr::from_str("127.0.0.1:3000").unwrap(); - let addr = InetAddr::from_std(&actual); - - match addr { - InetAddr::V4(addr) => { - let ip: u32 = 0x7f00_0001; - let port: u16 = 3000; - let saddr = addr.sin_addr.s_addr; - - assert_eq!(saddr, ip.to_be()); - assert_eq!(addr.sin_port, port.to_be()); - } - _ => panic!("nope"), - } - - assert_eq!(addr.to_string(), "127.0.0.1:3000"); - - let inet = addr.to_std(); - assert_eq!(actual, inet); -} - -#[allow(deprecated)] -#[test] -pub fn test_inetv4_addr_roundtrip_sockaddr_storage_to_addr() { - use nix::sys::socket::{sockaddr_storage_to_addr, SockAddr}; - - let actual: net::SocketAddr = FromStr::from_str("127.0.0.1:3000").unwrap(); - let addr = InetAddr::from_std(&actual); - let sockaddr = SockAddr::new_inet(addr); - - let (storage, ffi_size) = { - let mut storage = MaybeUninit::<sockaddr_storage>::zeroed(); - let storage_ptr = storage.as_mut_ptr().cast::<sockaddr>(); - let (ffi_ptr, ffi_size) = sockaddr.as_ffi_pair(); - assert_eq!(mem::size_of::<sockaddr>(), ffi_size as usize); - unsafe { - storage_ptr.copy_from_nonoverlapping(ffi_ptr as *const sockaddr, 1); - (storage.assume_init(), ffi_size) - } - }; - - let from_storage = - sockaddr_storage_to_addr(&storage, ffi_size as usize).unwrap(); - assert_eq!(from_storage, sockaddr); - let from_storage = - sockaddr_storage_to_addr(&storage, mem::size_of::<sockaddr_storage>()) - .unwrap(); - assert_eq!(from_storage, sockaddr); -} - -#[cfg(any(target_os = "linux"))] -#[cfg_attr(qemu, ignore)] -#[test] -pub fn test_timestamping() { - use nix::sys::socket::{ - recvmsg, sendmsg, setsockopt, socket, sockopt::Timestamping, - ControlMessageOwned, MsgFlags, SockFlag, SockType, SockaddrIn, - TimestampingFlag, - }; - use std::io::{IoSlice, IoSliceMut}; - - let sock_addr = SockaddrIn::from_str("127.0.0.1:6790").unwrap(); - - let ssock = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .expect("send socket failed"); - - let rsock = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .unwrap(); - nix::sys::socket::bind(rsock, &sock_addr).unwrap(); - - setsockopt(rsock, Timestamping, &TimestampingFlag::all()).unwrap(); - - let sbuf = [0u8; 2048]; - let mut rbuf = [0u8; 2048]; - let flags = MsgFlags::empty(); - let iov1 = [IoSlice::new(&sbuf)]; - let mut iov2 = [IoSliceMut::new(&mut rbuf)]; - - let mut cmsg = cmsg_space!(nix::sys::socket::Timestamps); - sendmsg(ssock, &iov1, &[], flags, Some(&sock_addr)).unwrap(); - let recv = recvmsg::<()>(rsock, &mut iov2, Some(&mut cmsg), flags).unwrap(); - - let mut ts = None; - for c in recv.cmsgs() { - if let ControlMessageOwned::ScmTimestampsns(timestamps) = c { - ts = Some(timestamps.system); - } - } - let ts = ts.expect("ScmTimestampns is present"); - let sys_time = - ::nix::time::clock_gettime(::nix::time::ClockId::CLOCK_REALTIME) - .unwrap(); - let diff = if ts > sys_time { - ts - sys_time - } else { - sys_time - ts - }; - assert!(std::time::Duration::from(diff).as_secs() < 60); -} - -#[allow(deprecated)] -#[test] -pub fn test_inetv6_addr_roundtrip_sockaddr_storage_to_addr() { - use nix::sys::socket::{sockaddr_storage_to_addr, SockAddr}; - - let port: u16 = 3000; - let flowinfo: u32 = 1; - let scope_id: u32 = 2; - let ip: Ipv6Addr = "fe80::1".parse().unwrap(); - - let actual = - SocketAddr::V6(SocketAddrV6::new(ip, port, flowinfo, scope_id)); - let addr = InetAddr::from_std(&actual); - let sockaddr = SockAddr::new_inet(addr); - - let (storage, ffi_size) = { - let mut storage = MaybeUninit::<sockaddr_storage>::zeroed(); - let storage_ptr = storage.as_mut_ptr().cast::<sockaddr_in6>(); - let (ffi_ptr, ffi_size) = sockaddr.as_ffi_pair(); - assert_eq!(mem::size_of::<sockaddr_in6>(), ffi_size as usize); - unsafe { - storage_ptr.copy_from_nonoverlapping( - (ffi_ptr as *const sockaddr).cast::<sockaddr_in6>(), - 1, - ); - (storage.assume_init(), ffi_size) - } - }; - - let from_storage = - sockaddr_storage_to_addr(&storage, ffi_size as usize).unwrap(); - assert_eq!(from_storage, sockaddr); - let from_storage = - sockaddr_storage_to_addr(&storage, mem::size_of::<sockaddr_storage>()) - .unwrap(); - assert_eq!(from_storage, sockaddr); -} - -#[test] -pub fn test_path_to_sock_addr() { - let path = "/foo/bar"; - let actual = Path::new(path); - let addr = UnixAddr::new(actual).unwrap(); - - let expect: &[c_char] = unsafe { - slice::from_raw_parts(path.as_ptr() as *const c_char, path.len()) - }; - assert_eq!(unsafe { &(*addr.as_ptr()).sun_path[..8] }, expect); - - assert_eq!(addr.path(), Some(actual)); -} - -fn calculate_hash<T: Hash>(t: &T) -> u64 { - let mut s = DefaultHasher::new(); - t.hash(&mut s); - s.finish() -} - -#[test] -pub fn test_addr_equality_path() { - let path = "/foo/bar"; - let actual = Path::new(path); - let addr1 = UnixAddr::new(actual).unwrap(); - let mut addr2 = addr1; - - unsafe { (*addr2.as_mut_ptr()).sun_path[10] = 127 }; - - assert_eq!(addr1, addr2); - assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2)); -} - -#[cfg(any(target_os = "android", target_os = "linux"))] -#[test] -pub fn test_abstract_sun_path_too_long() { - let name = String::from("nix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0testttttnix\0abstract\0test\0make\0sure\0this\0is\0long\0enough"); - let addr = UnixAddr::new_abstract(name.as_bytes()); - addr.expect_err("assertion failed"); -} - -#[cfg(any(target_os = "android", target_os = "linux"))] -#[test] -pub fn test_addr_equality_abstract() { - let name = String::from("nix\0abstract\0test"); - let addr1 = UnixAddr::new_abstract(name.as_bytes()).unwrap(); - let mut addr2 = addr1; - - assert_eq!(addr1, addr2); - assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2)); - - unsafe { (*addr2.as_mut_ptr()).sun_path[17] = 127 }; - assert_ne!(addr1, addr2); - assert_ne!(calculate_hash(&addr1), calculate_hash(&addr2)); -} - -// Test getting/setting abstract addresses (without unix socket creation) -#[cfg(any(target_os = "android", target_os = "linux"))] -#[test] -pub fn test_abstract_uds_addr() { - let empty = String::new(); - let addr = UnixAddr::new_abstract(empty.as_bytes()).unwrap(); - let sun_path: [u8; 0] = []; - assert_eq!(addr.as_abstract(), Some(&sun_path[..])); - - let name = String::from("nix\0abstract\0test"); - let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap(); - let sun_path = [ - 110u8, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, 116, 101, - 115, 116, - ]; - assert_eq!(addr.as_abstract(), Some(&sun_path[..])); - assert_eq!(addr.path(), None); - - // Internally, name is null-prefixed (abstract namespace) - assert_eq!(unsafe { (*addr.as_ptr()).sun_path[0] }, 0); -} - -// Test getting an unnamed address (without unix socket creation) -#[cfg(any(target_os = "android", target_os = "linux"))] -#[test] -pub fn test_unnamed_uds_addr() { - use crate::nix::sys::socket::SockaddrLike; - - let addr = UnixAddr::new_unnamed(); - - assert!(addr.is_unnamed()); - assert_eq!(addr.len(), 2); - assert!(addr.path().is_none()); - assert_eq!(addr.path_len(), 0); - - assert!(addr.as_abstract().is_none()); -} - -#[test] -pub fn test_getsockname() { - use nix::sys::socket::bind; - use nix::sys::socket::{socket, AddressFamily, SockFlag, SockType}; - - let tempdir = tempfile::tempdir().unwrap(); - let sockname = tempdir.path().join("sock"); - let sock = socket( - AddressFamily::Unix, - SockType::Stream, - SockFlag::empty(), - None, - ) - .expect("socket failed"); - let sockaddr = UnixAddr::new(&sockname).unwrap(); - bind(sock, &sockaddr).expect("bind failed"); - assert_eq!(sockaddr, getsockname(sock).expect("getsockname failed")); -} - -#[test] -pub fn test_socketpair() { - use nix::sys::socket::{socketpair, AddressFamily, SockFlag, SockType}; - use nix::unistd::{read, write}; - - let (fd1, fd2) = socketpair( - AddressFamily::Unix, - SockType::Stream, - None, - SockFlag::empty(), - ) - .unwrap(); - write(fd1, b"hello").unwrap(); - let mut buf = [0; 5]; - read(fd2, &mut buf).unwrap(); - - assert_eq!(&buf[..], b"hello"); -} - -#[test] -pub fn test_std_conversions() { - use nix::sys::socket::*; - - let std_sa = SocketAddrV4::from_str("127.0.0.1:6789").unwrap(); - let sock_addr = SockaddrIn::from(std_sa); - assert_eq!(std_sa, sock_addr.into()); - - let std_sa = SocketAddrV6::from_str("[::1]:6000").unwrap(); - let sock_addr: SockaddrIn6 = SockaddrIn6::from(std_sa); - assert_eq!(std_sa, sock_addr.into()); -} - -mod recvfrom { - use super::*; - use nix::sys::socket::*; - use nix::{errno::Errno, Result}; - use std::thread; - - const MSG: &[u8] = b"Hello, World!"; - - fn sendrecv<Fs, Fr>( - rsock: RawFd, - ssock: RawFd, - f_send: Fs, - mut f_recv: Fr, - ) -> Option<SockaddrStorage> - where - Fs: Fn(RawFd, &[u8], MsgFlags) -> Result<usize> + Send + 'static, - Fr: FnMut(usize, Option<SockaddrStorage>), - { - let mut buf: [u8; 13] = [0u8; 13]; - let mut l = 0; - let mut from = None; - - let send_thread = thread::spawn(move || { - let mut l = 0; - while l < std::mem::size_of_val(MSG) { - l += f_send(ssock, &MSG[l..], MsgFlags::empty()).unwrap(); - } - }); - - while l < std::mem::size_of_val(MSG) { - let (len, from_) = recvfrom(rsock, &mut buf[l..]).unwrap(); - f_recv(len, from_); - from = from_; - l += len; - } - assert_eq!(&buf, MSG); - send_thread.join().unwrap(); - from - } - - #[test] - pub fn stream() { - let (fd2, fd1) = socketpair( - AddressFamily::Unix, - SockType::Stream, - None, - SockFlag::empty(), - ) - .unwrap(); - // Ignore from for stream sockets - let _ = sendrecv(fd1, fd2, send, |_, _| {}); - } - - #[test] - pub fn udp() { - let std_sa = SocketAddrV4::from_str("127.0.0.1:6789").unwrap(); - let sock_addr = SockaddrIn::from(std_sa); - let rsock = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .unwrap(); - bind(rsock, &sock_addr).unwrap(); - let ssock = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .expect("send socket failed"); - let from = sendrecv( - rsock, - ssock, - move |s, m, flags| sendto(s, m, &sock_addr, flags), - |_, _| {}, - ); - // UDP sockets should set the from address - assert_eq!(AddressFamily::Inet, from.unwrap().family().unwrap()); - } - - #[cfg(target_os = "linux")] - mod udp_offload { - use super::*; - use nix::sys::socket::sockopt::{UdpGroSegment, UdpGsoSegment}; - use std::io::IoSlice; - - #[test] - // Disable the test under emulation because it fails in Cirrus-CI. Lack - // of QEMU support is suspected. - #[cfg_attr(qemu, ignore)] - pub fn gso() { - require_kernel_version!(udp_offload::gso, ">= 4.18"); - - // In this test, we send the data and provide a GSO segment size. - // Since we are sending the buffer of size 13, six UDP packets - // with size 2 and two UDP packet with size 1 will be sent. - let segment_size: u16 = 2; - - let sock_addr = SockaddrIn::new(127, 0, 0, 1, 6791); - let rsock = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .unwrap(); - - setsockopt(rsock, UdpGsoSegment, &(segment_size as _)) - .expect("setsockopt UDP_SEGMENT failed"); - - bind(rsock, &sock_addr).unwrap(); - let ssock = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .expect("send socket failed"); - - let mut num_packets_received: i32 = 0; - - sendrecv( - rsock, - ssock, - move |s, m, flags| { - let iov = [IoSlice::new(m)]; - let cmsg = ControlMessage::UdpGsoSegments(&segment_size); - sendmsg(s, &iov, &[cmsg], flags, Some(&sock_addr)) - }, - { - let num_packets_received_ref = &mut num_packets_received; - - move |len, _| { - // check that we receive UDP packets with payload size - // less or equal to segment size - assert!(len <= segment_size as usize); - *num_packets_received_ref += 1; - } - }, - ); - - // Buffer size is 13, we will receive six packets of size 2, - // and one packet of size 1. - assert_eq!(7, num_packets_received); - } - - #[test] - // Disable the test on emulated platforms because it fails in Cirrus-CI. - // Lack of QEMU support is suspected. - #[cfg_attr(qemu, ignore)] - pub fn gro() { - require_kernel_version!(udp_offload::gro, ">= 5.3"); - - // It's hard to guarantee receiving GRO packets. Just checking - // that `setsockopt` doesn't fail with error - - let rsock = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .unwrap(); - - setsockopt(rsock, UdpGroSegment, &true) - .expect("setsockopt UDP_GRO failed"); - } - } - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", - ))] - #[test] - pub fn udp_sendmmsg() { - use std::io::IoSlice; - - let std_sa = SocketAddrV4::from_str("127.0.0.1:6793").unwrap(); - let std_sa2 = SocketAddrV4::from_str("127.0.0.1:6794").unwrap(); - let sock_addr = SockaddrIn::from(std_sa); - let sock_addr2 = SockaddrIn::from(std_sa2); - - let rsock = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .unwrap(); - bind(rsock, &sock_addr).unwrap(); - let ssock = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .expect("send socket failed"); - - let from = sendrecv( - rsock, - ssock, - move |s, m, flags| { - let batch_size = 15; - let mut iovs = Vec::with_capacity(1 + batch_size); - let mut addrs = Vec::with_capacity(1 + batch_size); - let mut data = MultiHeaders::preallocate(1 + batch_size, None); - let iov = IoSlice::new(m); - // first chunk: - iovs.push([iov]); - addrs.push(Some(sock_addr)); - - for _ in 0..batch_size { - iovs.push([iov]); - addrs.push(Some(sock_addr2)); - } - - let res = sendmmsg(s, &mut data, &iovs, addrs, [], flags)?; - let mut sent_messages = 0; - let mut sent_bytes = 0; - for item in res { - sent_messages += 1; - sent_bytes += item.bytes; - } - // - assert_eq!(sent_messages, iovs.len()); - assert_eq!(sent_bytes, sent_messages * m.len()); - Ok(sent_messages) - }, - |_, _| {}, - ); - // UDP sockets should set the from address - assert_eq!(AddressFamily::Inet, from.unwrap().family().unwrap()); - } - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", - ))] - #[test] - pub fn udp_recvmmsg() { - use nix::sys::socket::{recvmmsg, MsgFlags}; - use std::io::IoSliceMut; - - const NUM_MESSAGES_SENT: usize = 2; - const DATA: [u8; 2] = [1, 2]; - - let inet_addr = SocketAddrV4::from_str("127.0.0.1:6798").unwrap(); - let sock_addr = SockaddrIn::from(inet_addr); - - let rsock = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .unwrap(); - bind(rsock, &sock_addr).unwrap(); - let ssock = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .expect("send socket failed"); - - let send_thread = thread::spawn(move || { - for _ in 0..NUM_MESSAGES_SENT { - sendto(ssock, &DATA[..], &sock_addr, MsgFlags::empty()) - .unwrap(); - } - }); - - let mut msgs = std::collections::LinkedList::new(); - - // Buffers to receive exactly `NUM_MESSAGES_SENT` messages - let mut receive_buffers = [[0u8; 32]; NUM_MESSAGES_SENT]; - msgs.extend( - receive_buffers - .iter_mut() - .map(|buf| [IoSliceMut::new(&mut buf[..])]), - ); - - let mut data = - MultiHeaders::<SockaddrIn>::preallocate(msgs.len(), None); - - let res: Vec<RecvMsg<SockaddrIn>> = - recvmmsg(rsock, &mut data, msgs.iter(), MsgFlags::empty(), None) - .expect("recvmmsg") - .collect(); - assert_eq!(res.len(), DATA.len()); - - for RecvMsg { address, bytes, .. } in res.into_iter() { - assert_eq!(AddressFamily::Inet, address.unwrap().family().unwrap()); - assert_eq!(DATA.len(), bytes); - } - - for buf in &receive_buffers { - assert_eq!(&buf[..DATA.len()], DATA); - } - - send_thread.join().unwrap(); - } - - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", - ))] - #[test] - pub fn udp_recvmmsg_dontwait_short_read() { - use nix::sys::socket::{recvmmsg, MsgFlags}; - use std::io::IoSliceMut; - - const NUM_MESSAGES_SENT: usize = 2; - const DATA: [u8; 4] = [1, 2, 3, 4]; - - let inet_addr = SocketAddrV4::from_str("127.0.0.1:6799").unwrap(); - let sock_addr = SockaddrIn::from(inet_addr); - - let rsock = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .unwrap(); - bind(rsock, &sock_addr).unwrap(); - let ssock = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .expect("send socket failed"); - - let send_thread = thread::spawn(move || { - for _ in 0..NUM_MESSAGES_SENT { - sendto(ssock, &DATA[..], &sock_addr, MsgFlags::empty()) - .unwrap(); - } - }); - // Ensure we've sent all the messages before continuing so `recvmmsg` - // will return right away - send_thread.join().unwrap(); - - let mut msgs = std::collections::LinkedList::new(); - - // Buffers to receive >`NUM_MESSAGES_SENT` messages to ensure `recvmmsg` - // will return when there are fewer than requested messages in the - // kernel buffers when using `MSG_DONTWAIT`. - let mut receive_buffers = [[0u8; 32]; NUM_MESSAGES_SENT + 2]; - msgs.extend( - receive_buffers - .iter_mut() - .map(|buf| [IoSliceMut::new(&mut buf[..])]), - ); - - let mut data = MultiHeaders::<SockaddrIn>::preallocate( - NUM_MESSAGES_SENT + 2, - None, - ); - - let res: Vec<RecvMsg<SockaddrIn>> = recvmmsg( - rsock, - &mut data, - msgs.iter(), - MsgFlags::MSG_DONTWAIT, - None, - ) - .expect("recvmmsg") - .collect(); - assert_eq!(res.len(), NUM_MESSAGES_SENT); - - for RecvMsg { address, bytes, .. } in res.into_iter() { - assert_eq!(AddressFamily::Inet, address.unwrap().family().unwrap()); - assert_eq!(DATA.len(), bytes); - } - - for buf in &receive_buffers[..NUM_MESSAGES_SENT] { - assert_eq!(&buf[..DATA.len()], DATA); - } - } - - #[test] - pub fn udp_inet6() { - let addr = std::net::Ipv6Addr::from_str("::1").unwrap(); - let rport = 6789; - let rstd_sa = SocketAddrV6::new(addr, rport, 0, 0); - let raddr = SockaddrIn6::from(rstd_sa); - let sport = 6790; - let sstd_sa = SocketAddrV6::new(addr, sport, 0, 0); - let saddr = SockaddrIn6::from(sstd_sa); - let rsock = socket( - AddressFamily::Inet6, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .expect("receive socket failed"); - match bind(rsock, &raddr) { - Err(Errno::EADDRNOTAVAIL) => { - println!("IPv6 not available, skipping test."); - return; - } - Err(e) => panic!("bind: {}", e), - Ok(()) => (), - } - let ssock = socket( - AddressFamily::Inet6, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .expect("send socket failed"); - bind(ssock, &saddr).unwrap(); - let from = sendrecv( - rsock, - ssock, - move |s, m, flags| sendto(s, m, &raddr, flags), - |_, _| {}, - ); - assert_eq!(AddressFamily::Inet6, from.unwrap().family().unwrap()); - let osent_addr = from.unwrap(); - let sent_addr = osent_addr.as_sockaddr_in6().unwrap(); - assert_eq!(sent_addr.ip(), addr); - assert_eq!(sent_addr.port(), sport); - } -} - -// Test error handling of our recvmsg wrapper -#[test] -pub fn test_recvmsg_ebadf() { - use nix::errno::Errno; - use nix::sys::socket::{recvmsg, MsgFlags}; - use std::io::IoSliceMut; - - let mut buf = [0u8; 5]; - let mut iov = [IoSliceMut::new(&mut buf[..])]; - - let fd = -1; // Bad file descriptor - let r = recvmsg::<()>(fd, &mut iov, None, MsgFlags::empty()); - - assert_eq!(r.err().unwrap(), Errno::EBADF); -} - -// Disable the test on emulated platforms due to a bug in QEMU versions < -// 2.12.0. https://bugs.launchpad.net/qemu/+bug/1701808 -#[cfg_attr(qemu, ignore)] -#[test] -pub fn test_scm_rights() { - use nix::sys::socket::{ - recvmsg, sendmsg, socketpair, AddressFamily, ControlMessage, - ControlMessageOwned, MsgFlags, SockFlag, SockType, - }; - use nix::unistd::{close, pipe, read, write}; - use std::io::{IoSlice, IoSliceMut}; - - let (fd1, fd2) = socketpair( - AddressFamily::Unix, - SockType::Stream, - None, - SockFlag::empty(), - ) - .unwrap(); - let (r, w) = pipe().unwrap(); - let mut received_r: Option<RawFd> = None; - - { - let iov = [IoSlice::new(b"hello")]; - let fds = [r]; - let cmsg = ControlMessage::ScmRights(&fds); - assert_eq!( - sendmsg::<()>(fd1, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(), - 5 - ); - close(r).unwrap(); - close(fd1).unwrap(); - } - - { - let mut buf = [0u8; 5]; - - let mut iov = [IoSliceMut::new(&mut buf[..])]; - let mut cmsgspace = cmsg_space!([RawFd; 1]); - let msg = recvmsg::<()>( - fd2, - &mut iov, - Some(&mut cmsgspace), - MsgFlags::empty(), - ) - .unwrap(); - - for cmsg in msg.cmsgs() { - if let ControlMessageOwned::ScmRights(fd) = cmsg { - assert_eq!(received_r, None); - assert_eq!(fd.len(), 1); - received_r = Some(fd[0]); - } else { - panic!("unexpected cmsg"); - } - } - assert_eq!(msg.bytes, 5); - assert!(!msg - .flags - .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); - close(fd2).unwrap(); - } - - let received_r = received_r.expect("Did not receive passed fd"); - // Ensure that the received file descriptor works - write(w, b"world").unwrap(); - let mut buf = [0u8; 5]; - read(received_r, &mut buf).unwrap(); - assert_eq!(&buf[..], b"world"); - close(received_r).unwrap(); - close(w).unwrap(); -} - -// Disable the test on emulated platforms due to not enabled support of AF_ALG in QEMU from rust cross -#[cfg(any(target_os = "linux", target_os = "android"))] -#[cfg_attr(qemu, ignore)] -#[test] -pub fn test_af_alg_cipher() { - use nix::sys::socket::sockopt::AlgSetKey; - use nix::sys::socket::{ - accept, bind, sendmsg, setsockopt, socket, AddressFamily, AlgAddr, - ControlMessage, MsgFlags, SockFlag, SockType, - }; - use nix::unistd::read; - use std::io::IoSlice; - - skip_if_cirrus!("Fails for an unknown reason Cirrus CI. Bug #1352"); - // Travis's seccomp profile blocks AF_ALG - // https://docs.docker.com/engine/security/seccomp/ - skip_if_seccomp!(test_af_alg_cipher); - - let alg_type = "skcipher"; - let alg_name = "ctr-aes-aesni"; - // 256-bits secret key - let key = vec![0u8; 32]; - // 16-bytes IV - let iv_len = 16; - let iv = vec![1u8; iv_len]; - // 256-bytes plain payload - let payload_len = 256; - let payload = vec![2u8; payload_len]; - - let sock = socket( - AddressFamily::Alg, - SockType::SeqPacket, - SockFlag::empty(), - None, - ) - .expect("socket failed"); - - let sockaddr = AlgAddr::new(alg_type, alg_name); - bind(sock, &sockaddr).expect("bind failed"); - - assert_eq!(sockaddr.alg_name().to_string_lossy(), alg_name); - assert_eq!(sockaddr.alg_type().to_string_lossy(), alg_type); - - setsockopt(sock, AlgSetKey::default(), &key).expect("setsockopt"); - let session_socket = accept(sock).expect("accept failed"); - - let msgs = [ - ControlMessage::AlgSetOp(&libc::ALG_OP_ENCRYPT), - ControlMessage::AlgSetIv(iv.as_slice()), - ]; - let iov = IoSlice::new(&payload); - sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None) - .expect("sendmsg encrypt"); - - // allocate buffer for encrypted data - let mut encrypted = vec![0u8; payload_len]; - let num_bytes = read(session_socket, &mut encrypted).expect("read encrypt"); - assert_eq!(num_bytes, payload_len); - - let iov = IoSlice::new(&encrypted); - - let iv = vec![1u8; iv_len]; - - let msgs = [ - ControlMessage::AlgSetOp(&libc::ALG_OP_DECRYPT), - ControlMessage::AlgSetIv(iv.as_slice()), - ]; - sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None) - .expect("sendmsg decrypt"); - - // allocate buffer for decrypted data - let mut decrypted = vec![0u8; payload_len]; - let num_bytes = read(session_socket, &mut decrypted).expect("read decrypt"); - - assert_eq!(num_bytes, payload_len); - assert_eq!(decrypted, payload); -} - -// Disable the test on emulated platforms due to not enabled support of AF_ALG -// in QEMU from rust cross -#[cfg(any(target_os = "linux", target_os = "android"))] -#[cfg_attr(qemu, ignore)] -#[test] -pub fn test_af_alg_aead() { - use libc::{ALG_OP_DECRYPT, ALG_OP_ENCRYPT}; - use nix::fcntl::{fcntl, FcntlArg, OFlag}; - use nix::sys::socket::sockopt::{AlgSetAeadAuthSize, AlgSetKey}; - use nix::sys::socket::{ - accept, bind, sendmsg, setsockopt, socket, AddressFamily, AlgAddr, - ControlMessage, MsgFlags, SockFlag, SockType, - }; - use nix::unistd::{close, read}; - use std::io::IoSlice; - - skip_if_cirrus!("Fails for an unknown reason Cirrus CI. Bug #1352"); - // Travis's seccomp profile blocks AF_ALG - // https://docs.docker.com/engine/security/seccomp/ - skip_if_seccomp!(test_af_alg_aead); - - let auth_size = 4usize; - let assoc_size = 16u32; - - let alg_type = "aead"; - let alg_name = "gcm(aes)"; - // 256-bits secret key - let key = vec![0u8; 32]; - // 12-bytes IV - let iv_len = 12; - let iv = vec![1u8; iv_len]; - // 256-bytes plain payload - let payload_len = 256; - let mut payload = - vec![2u8; payload_len + (assoc_size as usize) + auth_size]; - - for i in 0..assoc_size { - payload[i as usize] = 10; - } - - let len = payload.len(); - - for i in 0..auth_size { - payload[len - 1 - i] = 0; - } - - let sock = socket( - AddressFamily::Alg, - SockType::SeqPacket, - SockFlag::empty(), - None, - ) - .expect("socket failed"); - - let sockaddr = AlgAddr::new(alg_type, alg_name); - bind(sock, &sockaddr).expect("bind failed"); - - setsockopt(sock, AlgSetAeadAuthSize, &auth_size) - .expect("setsockopt AlgSetAeadAuthSize"); - setsockopt(sock, AlgSetKey::default(), &key).expect("setsockopt AlgSetKey"); - let session_socket = accept(sock).expect("accept failed"); - - let msgs = [ - ControlMessage::AlgSetOp(&ALG_OP_ENCRYPT), - ControlMessage::AlgSetIv(iv.as_slice()), - ControlMessage::AlgSetAeadAssoclen(&assoc_size), - ]; - - let iov = IoSlice::new(&payload); - sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None) - .expect("sendmsg encrypt"); - - // allocate buffer for encrypted data - let mut encrypted = - vec![0u8; (assoc_size as usize) + payload_len + auth_size]; - let num_bytes = read(session_socket, &mut encrypted).expect("read encrypt"); - assert_eq!(num_bytes, payload_len + auth_size + (assoc_size as usize)); - close(session_socket).expect("close"); - - for i in 0..assoc_size { - encrypted[i as usize] = 10; - } - - let iov = IoSlice::new(&encrypted); - - let iv = vec![1u8; iv_len]; - - let session_socket = accept(sock).expect("accept failed"); - - let msgs = [ - ControlMessage::AlgSetOp(&ALG_OP_DECRYPT), - ControlMessage::AlgSetIv(iv.as_slice()), - ControlMessage::AlgSetAeadAssoclen(&assoc_size), - ]; - sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None) - .expect("sendmsg decrypt"); - - // allocate buffer for decrypted data - let mut decrypted = - vec![0u8; payload_len + (assoc_size as usize) + auth_size]; - // Starting with kernel 4.9, the interface changed slightly such that the - // authentication tag memory is only needed in the output buffer for encryption - // and in the input buffer for decryption. - // Do not block on read, as we may have fewer bytes than buffer size - fcntl(session_socket, FcntlArg::F_SETFL(OFlag::O_NONBLOCK)) - .expect("fcntl non_blocking"); - let num_bytes = read(session_socket, &mut decrypted).expect("read decrypt"); - - assert!(num_bytes >= payload_len + (assoc_size as usize)); - assert_eq!( - decrypted[(assoc_size as usize)..(payload_len + (assoc_size as usize))], - payload[(assoc_size as usize)..payload_len + (assoc_size as usize)] - ); -} - -// Verify `ControlMessage::Ipv4PacketInfo` for `sendmsg`. -// This creates a (udp) socket bound to localhost, then sends a message to -// itself but uses Ipv4PacketInfo to force the source address to be localhost. -// -// This would be a more interesting test if we could assume that the test host -// has more than one IP address (since we could select a different address to -// test from). -#[cfg(any(target_os = "linux", target_os = "macos", target_os = "netbsd"))] -#[test] -pub fn test_sendmsg_ipv4packetinfo() { - use cfg_if::cfg_if; - use nix::sys::socket::{ - bind, sendmsg, socket, AddressFamily, ControlMessage, MsgFlags, - SockFlag, SockType, SockaddrIn, - }; - use std::io::IoSlice; - - let sock = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .expect("socket failed"); - - let sock_addr = SockaddrIn::new(127, 0, 0, 1, 4000); - - bind(sock, &sock_addr).expect("bind failed"); - - let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; - let iov = [IoSlice::new(&slice)]; - - cfg_if! { - if #[cfg(target_os = "netbsd")] { - let pi = libc::in_pktinfo { - ipi_ifindex: 0, /* Unspecified interface */ - ipi_addr: libc::in_addr { s_addr: 0 }, - }; - } else { - let pi = libc::in_pktinfo { - ipi_ifindex: 0, /* Unspecified interface */ - ipi_addr: libc::in_addr { s_addr: 0 }, - ipi_spec_dst: sock_addr.as_ref().sin_addr, - }; - } - } - - let cmsg = [ControlMessage::Ipv4PacketInfo(&pi)]; - - sendmsg(sock, &iov, &cmsg, MsgFlags::empty(), Some(&sock_addr)) - .expect("sendmsg"); -} - -// Verify `ControlMessage::Ipv6PacketInfo` for `sendmsg`. -// This creates a (udp) socket bound to ip6-localhost, then sends a message to -// itself but uses Ipv6PacketInfo to force the source address to be -// ip6-localhost. -// -// This would be a more interesting test if we could assume that the test host -// has more than one IP address (since we could select a different address to -// test from). -#[cfg(any( - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "freebsd" -))] -#[test] -pub fn test_sendmsg_ipv6packetinfo() { - use nix::errno::Errno; - use nix::sys::socket::{ - bind, sendmsg, socket, AddressFamily, ControlMessage, MsgFlags, - SockFlag, SockType, SockaddrIn6, - }; - use std::io::IoSlice; - - let sock = socket( - AddressFamily::Inet6, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .expect("socket failed"); - - let std_sa = SocketAddrV6::from_str("[::1]:6000").unwrap(); - let sock_addr: SockaddrIn6 = SockaddrIn6::from(std_sa); - - if let Err(Errno::EADDRNOTAVAIL) = bind(sock, &sock_addr) { - println!("IPv6 not available, skipping test."); - return; - } - - let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; - let iov = [IoSlice::new(&slice)]; - - let pi = libc::in6_pktinfo { - ipi6_ifindex: 0, /* Unspecified interface */ - ipi6_addr: sock_addr.as_ref().sin6_addr, - }; - - let cmsg = [ControlMessage::Ipv6PacketInfo(&pi)]; - - sendmsg::<SockaddrIn6>( - sock, - &iov, - &cmsg, - MsgFlags::empty(), - Some(&sock_addr), - ) - .expect("sendmsg"); -} - -// Verify that ControlMessage::Ipv4SendSrcAddr works for sendmsg. This -// creates a UDP socket bound to all local interfaces (0.0.0.0). It then -// sends message to itself at 127.0.0.1 while explicitly specifying -// 127.0.0.1 as the source address through an Ipv4SendSrcAddr -// (IP_SENDSRCADDR) control message. -// -// Note that binding to 0.0.0.0 is *required* on FreeBSD; sendmsg -// returns EINVAL otherwise. (See FreeBSD's ip(4) man page.) -#[cfg(any( - target_os = "netbsd", - target_os = "freebsd", - target_os = "openbsd", - target_os = "dragonfly", -))] -#[test] -pub fn test_sendmsg_ipv4sendsrcaddr() { - use nix::sys::socket::{ - bind, sendmsg, socket, AddressFamily, ControlMessage, MsgFlags, - SockFlag, SockType, SockaddrIn, - }; - use std::io::IoSlice; - - let sock = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .expect("socket failed"); - - let unspec_sock_addr = SockaddrIn::new(0, 0, 0, 0, 0); - bind(sock, &unspec_sock_addr).expect("bind failed"); - let bound_sock_addr: SockaddrIn = getsockname(sock).unwrap(); - let localhost_sock_addr: SockaddrIn = - SockaddrIn::new(127, 0, 0, 1, bound_sock_addr.port()); - - let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; - let iov = [IoSlice::new(&slice)]; - let cmsg = [ControlMessage::Ipv4SendSrcAddr( - &localhost_sock_addr.as_ref().sin_addr, - )]; - - sendmsg( - sock, - &iov, - &cmsg, - MsgFlags::empty(), - Some(&localhost_sock_addr), - ) - .expect("sendmsg"); -} - -/// Tests that passing multiple fds using a single `ControlMessage` works. -// Disable the test on emulated platforms due to a bug in QEMU versions < -// 2.12.0. https://bugs.launchpad.net/qemu/+bug/1701808 -#[cfg_attr(qemu, ignore)] -#[test] -fn test_scm_rights_single_cmsg_multiple_fds() { - use nix::sys::socket::{ - recvmsg, sendmsg, ControlMessage, ControlMessageOwned, MsgFlags, - }; - use std::io::{IoSlice, IoSliceMut}; - use std::os::unix::io::{AsRawFd, RawFd}; - use std::os::unix::net::UnixDatagram; - use std::thread; - - let (send, receive) = UnixDatagram::pair().unwrap(); - let thread = thread::spawn(move || { - let mut buf = [0u8; 8]; - let mut iovec = [IoSliceMut::new(&mut buf)]; - - let mut space = cmsg_space!([RawFd; 2]); - let msg = recvmsg::<()>( - receive.as_raw_fd(), - &mut iovec, - Some(&mut space), - MsgFlags::empty(), - ) - .unwrap(); - assert!(!msg - .flags - .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); - - let mut cmsgs = msg.cmsgs(); - match cmsgs.next() { - Some(ControlMessageOwned::ScmRights(fds)) => { - assert_eq!( - fds.len(), - 2, - "unexpected fd count (expected 2 fds, got {})", - fds.len() - ); - } - _ => panic!(), - } - assert!(cmsgs.next().is_none(), "unexpected control msg"); - - assert_eq!(msg.bytes, 8); - assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]); - }); - - let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; - let iov = [IoSlice::new(&slice)]; - let fds = [libc::STDIN_FILENO, libc::STDOUT_FILENO]; // pass stdin and stdout - let cmsg = [ControlMessage::ScmRights(&fds)]; - sendmsg::<()>(send.as_raw_fd(), &iov, &cmsg, MsgFlags::empty(), None) - .unwrap(); - thread.join().unwrap(); -} - -// Verify `sendmsg` builds a valid `msghdr` when passing an empty -// `cmsgs` argument. This should result in a msghdr with a nullptr -// msg_control field and a msg_controllen of 0 when calling into the -// raw `sendmsg`. -#[test] -pub fn test_sendmsg_empty_cmsgs() { - use nix::sys::socket::{ - recvmsg, sendmsg, socketpair, AddressFamily, MsgFlags, SockFlag, - SockType, - }; - use nix::unistd::close; - use std::io::{IoSlice, IoSliceMut}; - - let (fd1, fd2) = socketpair( - AddressFamily::Unix, - SockType::Stream, - None, - SockFlag::empty(), - ) - .unwrap(); - - { - let iov = [IoSlice::new(b"hello")]; - assert_eq!( - sendmsg::<()>(fd1, &iov, &[], MsgFlags::empty(), None).unwrap(), - 5 - ); - close(fd1).unwrap(); - } - - { - let mut buf = [0u8; 5]; - let mut iov = [IoSliceMut::new(&mut buf[..])]; - - let mut cmsgspace = cmsg_space!([RawFd; 1]); - let msg = recvmsg::<()>( - fd2, - &mut iov, - Some(&mut cmsgspace), - MsgFlags::empty(), - ) - .unwrap(); - - for _ in msg.cmsgs() { - panic!("unexpected cmsg"); - } - assert!(!msg - .flags - .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); - assert_eq!(msg.bytes, 5); - close(fd2).unwrap(); - } -} - -#[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "freebsd", - target_os = "dragonfly", -))] -#[test] -fn test_scm_credentials() { - use nix::sys::socket::{ - recvmsg, sendmsg, socketpair, AddressFamily, ControlMessage, - ControlMessageOwned, MsgFlags, SockFlag, SockType, UnixCredentials, - }; - #[cfg(any(target_os = "android", target_os = "linux"))] - use nix::sys::socket::{setsockopt, sockopt::PassCred}; - use nix::unistd::{close, getgid, getpid, getuid}; - use std::io::{IoSlice, IoSliceMut}; - - let (send, recv) = socketpair( - AddressFamily::Unix, - SockType::Stream, - None, - SockFlag::empty(), - ) - .unwrap(); - #[cfg(any(target_os = "android", target_os = "linux"))] - setsockopt(recv, PassCred, &true).unwrap(); - - { - let iov = [IoSlice::new(b"hello")]; - #[cfg(any(target_os = "android", target_os = "linux"))] - let cred = UnixCredentials::new(); - #[cfg(any(target_os = "android", target_os = "linux"))] - let cmsg = ControlMessage::ScmCredentials(&cred); - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - let cmsg = ControlMessage::ScmCreds; - assert_eq!( - sendmsg::<()>(send, &iov, &[cmsg], MsgFlags::empty(), None) - .unwrap(), - 5 - ); - close(send).unwrap(); - } - - { - let mut buf = [0u8; 5]; - let mut iov = [IoSliceMut::new(&mut buf[..])]; - - let mut cmsgspace = cmsg_space!(UnixCredentials); - let msg = recvmsg::<()>( - recv, - &mut iov, - Some(&mut cmsgspace), - MsgFlags::empty(), - ) - .unwrap(); - let mut received_cred = None; - - for cmsg in msg.cmsgs() { - let cred = match cmsg { - #[cfg(any(target_os = "android", target_os = "linux"))] - ControlMessageOwned::ScmCredentials(cred) => cred, - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - ControlMessageOwned::ScmCreds(cred) => cred, - other => panic!("unexpected cmsg {:?}", other), - }; - assert!(received_cred.is_none()); - assert_eq!(cred.pid(), getpid().as_raw()); - assert_eq!(cred.uid(), getuid().as_raw()); - assert_eq!(cred.gid(), getgid().as_raw()); - received_cred = Some(cred); - } - received_cred.expect("no creds received"); - assert_eq!(msg.bytes, 5); - assert!(!msg - .flags - .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); - close(recv).unwrap(); - } -} - -/// Ensure that we can send `SCM_CREDENTIALS` and `SCM_RIGHTS` with a single -/// `sendmsg` call. -#[cfg(any(target_os = "android", target_os = "linux"))] -// qemu's handling of multiple cmsgs is bugged, ignore tests under emulation -// see https://bugs.launchpad.net/qemu/+bug/1781280 -#[cfg_attr(qemu, ignore)] -#[test] -fn test_scm_credentials_and_rights() { - let space = cmsg_space!(libc::ucred, RawFd); - test_impl_scm_credentials_and_rights(space); -} - -/// Ensure that passing a an oversized control message buffer to recvmsg -/// still works. -#[cfg(any(target_os = "android", target_os = "linux"))] -// qemu's handling of multiple cmsgs is bugged, ignore tests under emulation -// see https://bugs.launchpad.net/qemu/+bug/1781280 -#[cfg_attr(qemu, ignore)] -#[test] -fn test_too_large_cmsgspace() { - let space = vec![0u8; 1024]; - test_impl_scm_credentials_and_rights(space); -} - -#[cfg(any(target_os = "android", target_os = "linux"))] -fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) { - use libc::ucred; - use nix::sys::socket::sockopt::PassCred; - use nix::sys::socket::{ - recvmsg, sendmsg, setsockopt, socketpair, ControlMessage, - ControlMessageOwned, MsgFlags, SockFlag, SockType, - }; - use nix::unistd::{close, getgid, getpid, getuid, pipe, write}; - use std::io::{IoSlice, IoSliceMut}; - - let (send, recv) = socketpair( - AddressFamily::Unix, - SockType::Stream, - None, - SockFlag::empty(), - ) - .unwrap(); - setsockopt(recv, PassCred, &true).unwrap(); - - let (r, w) = pipe().unwrap(); - let mut received_r: Option<RawFd> = None; - - { - let iov = [IoSlice::new(b"hello")]; - let cred = ucred { - pid: getpid().as_raw(), - uid: getuid().as_raw(), - gid: getgid().as_raw(), - } - .into(); - let fds = [r]; - let cmsgs = [ - ControlMessage::ScmCredentials(&cred), - ControlMessage::ScmRights(&fds), - ]; - assert_eq!( - sendmsg::<()>(send, &iov, &cmsgs, MsgFlags::empty(), None).unwrap(), - 5 - ); - close(r).unwrap(); - close(send).unwrap(); - } - - { - let mut buf = [0u8; 5]; - let mut iov = [IoSliceMut::new(&mut buf[..])]; - let msg = - recvmsg::<()>(recv, &mut iov, Some(&mut space), MsgFlags::empty()) - .unwrap(); - let mut received_cred = None; - - assert_eq!(msg.cmsgs().count(), 2, "expected 2 cmsgs"); - - for cmsg in msg.cmsgs() { - match cmsg { - ControlMessageOwned::ScmRights(fds) => { - assert_eq!(received_r, None, "already received fd"); - assert_eq!(fds.len(), 1); - received_r = Some(fds[0]); - } - ControlMessageOwned::ScmCredentials(cred) => { - assert!(received_cred.is_none()); - assert_eq!(cred.pid(), getpid().as_raw()); - assert_eq!(cred.uid(), getuid().as_raw()); - assert_eq!(cred.gid(), getgid().as_raw()); - received_cred = Some(cred); - } - _ => panic!("unexpected cmsg"), - } - } - received_cred.expect("no creds received"); - assert_eq!(msg.bytes, 5); - assert!(!msg - .flags - .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); - close(recv).unwrap(); - } - - let received_r = received_r.expect("Did not receive passed fd"); - // Ensure that the received file descriptor works - write(w, b"world").unwrap(); - let mut buf = [0u8; 5]; - read(received_r, &mut buf).unwrap(); - assert_eq!(&buf[..], b"world"); - close(received_r).unwrap(); - close(w).unwrap(); -} - -// Test creating and using named unix domain sockets -#[test] -pub fn test_named_unixdomain() { - use nix::sys::socket::{accept, bind, connect, listen, socket, UnixAddr}; - use nix::sys::socket::{SockFlag, SockType}; - use nix::unistd::{close, read, write}; - use std::thread; - - let tempdir = tempfile::tempdir().unwrap(); - let sockname = tempdir.path().join("sock"); - let s1 = socket( - AddressFamily::Unix, - SockType::Stream, - SockFlag::empty(), - None, - ) - .expect("socket failed"); - let sockaddr = UnixAddr::new(&sockname).unwrap(); - bind(s1, &sockaddr).expect("bind failed"); - listen(s1, 10).expect("listen failed"); - - let thr = thread::spawn(move || { - let s2 = socket( - AddressFamily::Unix, - SockType::Stream, - SockFlag::empty(), - None, - ) - .expect("socket failed"); - connect(s2, &sockaddr).expect("connect failed"); - write(s2, b"hello").expect("write failed"); - close(s2).unwrap(); - }); - - let s3 = accept(s1).expect("accept failed"); - - let mut buf = [0; 5]; - read(s3, &mut buf).unwrap(); - close(s3).unwrap(); - close(s1).unwrap(); - thr.join().unwrap(); - - assert_eq!(&buf[..], b"hello"); -} - -// Test using unnamed unix domain addresses -#[cfg(any(target_os = "android", target_os = "linux"))] -#[test] -pub fn test_unnamed_unixdomain() { - use nix::sys::socket::{getsockname, socketpair}; - use nix::sys::socket::{SockFlag, SockType}; - use nix::unistd::close; - - let (fd_1, fd_2) = socketpair( - AddressFamily::Unix, - SockType::Stream, - None, - SockFlag::empty(), - ) - .expect("socketpair failed"); - - let addr_1: UnixAddr = getsockname(fd_1).expect("getsockname failed"); - assert!(addr_1.is_unnamed()); - - close(fd_1).unwrap(); - close(fd_2).unwrap(); -} - -// Test creating and using unnamed unix domain addresses for autobinding sockets -#[cfg(any(target_os = "android", target_os = "linux"))] -#[test] -pub fn test_unnamed_unixdomain_autobind() { - use nix::sys::socket::{bind, getsockname, socket}; - use nix::sys::socket::{SockFlag, SockType}; - use nix::unistd::close; - - let fd = socket( - AddressFamily::Unix, - SockType::Stream, - SockFlag::empty(), - None, - ) - .expect("socket failed"); - - // unix(7): "If a bind(2) call specifies addrlen as `sizeof(sa_family_t)`, or [...], then the - // socket is autobound to an abstract address" - bind(fd, &UnixAddr::new_unnamed()).expect("bind failed"); - - let addr: UnixAddr = getsockname(fd).expect("getsockname failed"); - let addr = addr.as_abstract().unwrap(); - - // changed from 8 to 5 bytes in Linux 2.3.15, and rust's minimum supported Linux version is 3.2 - // (as of 2022-11) - assert_eq!(addr.len(), 5); - - close(fd).unwrap(); -} - -// Test creating and using named system control sockets -#[cfg(any(target_os = "macos", target_os = "ios"))] -#[test] -pub fn test_syscontrol() { - use nix::errno::Errno; - use nix::sys::socket::{ - socket, SockFlag, SockProtocol, SockType, SysControlAddr, - }; - - let fd = socket( - AddressFamily::System, - SockType::Datagram, - SockFlag::empty(), - SockProtocol::KextControl, - ) - .expect("socket failed"); - SysControlAddr::from_name(fd, "com.apple.net.utun_control", 0) - .expect("resolving sys_control name failed"); - assert_eq!( - SysControlAddr::from_name(fd, "foo.bar.lol", 0).err(), - Some(Errno::ENOENT) - ); - - // requires root privileges - // connect(fd, &sockaddr).expect("connect failed"); -} - -#[cfg(any( - target_os = "android", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", -))] -fn loopback_address( - family: AddressFamily, -) -> Option<nix::ifaddrs::InterfaceAddress> { - use nix::ifaddrs::getifaddrs; - use nix::net::if_::*; - use nix::sys::socket::SockaddrLike; - use std::io; - use std::io::Write; - - let mut addrs = match getifaddrs() { - Ok(iter) => iter, - Err(e) => { - let stdioerr = io::stderr(); - let mut handle = stdioerr.lock(); - writeln!(handle, "getifaddrs: {:?}", e).unwrap(); - return None; - } - }; - // return first address matching family - addrs.find(|ifaddr| { - ifaddr.flags.contains(InterfaceFlags::IFF_LOOPBACK) - && ifaddr.address.as_ref().and_then(SockaddrLike::family) - == Some(family) - }) -} - -#[cfg(any( - target_os = "android", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", -))] -// qemu doesn't seem to be emulating this correctly in these architectures -#[cfg_attr( - all( - qemu, - any( - target_arch = "mips", - target_arch = "mips64", - target_arch = "powerpc64", - ) - ), - ignore -)] -#[test] -pub fn test_recv_ipv4pktinfo() { - use nix::net::if_::*; - use nix::sys::socket::sockopt::Ipv4PacketInfo; - use nix::sys::socket::{bind, SockFlag, SockType, SockaddrIn}; - use nix::sys::socket::{getsockname, setsockopt, socket}; - use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags}; - use std::io::{IoSlice, IoSliceMut}; - - let lo_ifaddr = loopback_address(AddressFamily::Inet); - let (lo_name, lo) = match lo_ifaddr { - Some(ifaddr) => ( - ifaddr.interface_name, - ifaddr.address.expect("Expect IPv4 address on interface"), - ), - None => return, - }; - let receive = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .expect("receive socket failed"); - bind(receive, &lo).expect("bind failed"); - let sa: SockaddrIn = getsockname(receive).expect("getsockname failed"); - setsockopt(receive, Ipv4PacketInfo, &true).expect("setsockopt failed"); - - { - let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; - let iov = [IoSlice::new(&slice)]; - - let send = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .expect("send socket failed"); - sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa)) - .expect("sendmsg failed"); - } - - { - let mut buf = [0u8; 8]; - let mut iovec = [IoSliceMut::new(&mut buf)]; - - let mut space = cmsg_space!(libc::in_pktinfo); - let msg = recvmsg::<()>( - receive, - &mut iovec, - Some(&mut space), - MsgFlags::empty(), - ) - .expect("recvmsg failed"); - assert!(!msg - .flags - .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); - - let mut cmsgs = msg.cmsgs(); - if let Some(ControlMessageOwned::Ipv4PacketInfo(pktinfo)) = cmsgs.next() - { - let i = if_nametoindex(lo_name.as_bytes()).expect("if_nametoindex"); - assert_eq!( - pktinfo.ipi_ifindex as libc::c_uint, i, - "unexpected ifindex (expected {}, got {})", - i, pktinfo.ipi_ifindex - ); - } - assert!(cmsgs.next().is_none(), "unexpected additional control msg"); - assert_eq!(msg.bytes, 8); - assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]); - } -} - -#[cfg(any( - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", -))] -// qemu doesn't seem to be emulating this correctly in these architectures -#[cfg_attr( - all( - qemu, - any( - target_arch = "mips", - target_arch = "mips64", - target_arch = "powerpc64", - ) - ), - ignore -)] -#[test] -pub fn test_recvif() { - use nix::net::if_::*; - use nix::sys::socket::sockopt::{Ipv4RecvDstAddr, Ipv4RecvIf}; - use nix::sys::socket::{bind, SockFlag, SockType, SockaddrIn}; - use nix::sys::socket::{getsockname, setsockopt, socket}; - use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags}; - use std::io::{IoSlice, IoSliceMut}; - - let lo_ifaddr = loopback_address(AddressFamily::Inet); - let (lo_name, lo) = match lo_ifaddr { - Some(ifaddr) => ( - ifaddr.interface_name, - ifaddr.address.expect("Expect IPv4 address on interface"), - ), - None => return, - }; - let receive = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .expect("receive socket failed"); - bind(receive, &lo).expect("bind failed"); - let sa: SockaddrIn = getsockname(receive).expect("getsockname failed"); - setsockopt(receive, Ipv4RecvIf, &true) - .expect("setsockopt IP_RECVIF failed"); - setsockopt(receive, Ipv4RecvDstAddr, &true) - .expect("setsockopt IP_RECVDSTADDR failed"); - - { - let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; - let iov = [IoSlice::new(&slice)]; - - let send = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .expect("send socket failed"); - sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa)) - .expect("sendmsg failed"); - } - - { - let mut buf = [0u8; 8]; - let mut iovec = [IoSliceMut::new(&mut buf)]; - let mut space = cmsg_space!(libc::sockaddr_dl, libc::in_addr); - let msg = recvmsg::<()>( - receive, - &mut iovec, - Some(&mut space), - MsgFlags::empty(), - ) - .expect("recvmsg failed"); - assert!(!msg - .flags - .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); - assert_eq!(msg.cmsgs().count(), 2, "expected 2 cmsgs"); - - let mut rx_recvif = false; - let mut rx_recvdstaddr = false; - for cmsg in msg.cmsgs() { - match cmsg { - ControlMessageOwned::Ipv4RecvIf(dl) => { - rx_recvif = true; - let i = if_nametoindex(lo_name.as_bytes()) - .expect("if_nametoindex"); - assert_eq!( - dl.sdl_index as libc::c_uint, i, - "unexpected ifindex (expected {}, got {})", - i, dl.sdl_index - ); - } - ControlMessageOwned::Ipv4RecvDstAddr(addr) => { - rx_recvdstaddr = true; - if let Some(sin) = lo.as_sockaddr_in() { - assert_eq!(sin.as_ref().sin_addr.s_addr, - addr.s_addr, - "unexpected destination address (expected {}, got {})", - sin.as_ref().sin_addr.s_addr, - addr.s_addr); - } else { - panic!("unexpected Sockaddr"); - } - } - _ => panic!("unexpected additional control msg"), - } - } - assert!(rx_recvif); - assert!(rx_recvdstaddr); - assert_eq!(msg.bytes, 8); - assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]); - } -} - -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] -#[cfg_attr(qemu, ignore)] -#[test] -pub fn test_recvif_ipv4() { - use nix::sys::socket::sockopt::Ipv4OrigDstAddr; - use nix::sys::socket::{bind, SockFlag, SockType, SockaddrIn}; - use nix::sys::socket::{getsockname, setsockopt, socket}; - use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags}; - use std::io::{IoSlice, IoSliceMut}; - - let lo_ifaddr = loopback_address(AddressFamily::Inet); - let (_lo_name, lo) = match lo_ifaddr { - Some(ifaddr) => ( - ifaddr.interface_name, - ifaddr.address.expect("Expect IPv4 address on interface"), - ), - None => return, - }; - let receive = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .expect("receive socket failed"); - bind(receive, &lo).expect("bind failed"); - let sa: SockaddrIn = getsockname(receive).expect("getsockname failed"); - setsockopt(receive, Ipv4OrigDstAddr, &true) - .expect("setsockopt IP_ORIGDSTADDR failed"); - - { - let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; - let iov = [IoSlice::new(&slice)]; - - let send = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .expect("send socket failed"); - sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa)) - .expect("sendmsg failed"); - } - - { - let mut buf = [0u8; 8]; - let mut iovec = [IoSliceMut::new(&mut buf)]; - let mut space = cmsg_space!(libc::sockaddr_in); - let msg = recvmsg::<()>( - receive, - &mut iovec, - Some(&mut space), - MsgFlags::empty(), - ) - .expect("recvmsg failed"); - assert!(!msg - .flags - .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); - assert_eq!(msg.cmsgs().count(), 1, "expected 1 cmsgs"); - - let mut rx_recvorigdstaddr = false; - for cmsg in msg.cmsgs() { - match cmsg { - ControlMessageOwned::Ipv4OrigDstAddr(addr) => { - rx_recvorigdstaddr = true; - if let Some(sin) = lo.as_sockaddr_in() { - assert_eq!(sin.as_ref().sin_addr.s_addr, - addr.sin_addr.s_addr, - "unexpected destination address (expected {}, got {})", - sin.as_ref().sin_addr.s_addr, - addr.sin_addr.s_addr); - } else { - panic!("unexpected Sockaddr"); - } - } - _ => panic!("unexpected additional control msg"), - } - } - assert!(rx_recvorigdstaddr); - assert_eq!(msg.bytes, 8); - assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]); - } -} - -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] -#[cfg_attr(qemu, ignore)] -#[test] -pub fn test_recvif_ipv6() { - use nix::sys::socket::sockopt::Ipv6OrigDstAddr; - use nix::sys::socket::{bind, SockFlag, SockType, SockaddrIn6}; - use nix::sys::socket::{getsockname, setsockopt, socket}; - use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags}; - use std::io::{IoSlice, IoSliceMut}; - - let lo_ifaddr = loopback_address(AddressFamily::Inet6); - let (_lo_name, lo) = match lo_ifaddr { - Some(ifaddr) => ( - ifaddr.interface_name, - ifaddr.address.expect("Expect IPv6 address on interface"), - ), - None => return, - }; - let receive = socket( - AddressFamily::Inet6, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .expect("receive socket failed"); - bind(receive, &lo).expect("bind failed"); - let sa: SockaddrIn6 = getsockname(receive).expect("getsockname failed"); - setsockopt(receive, Ipv6OrigDstAddr, &true) - .expect("setsockopt IP_ORIGDSTADDR failed"); - - { - let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; - let iov = [IoSlice::new(&slice)]; - - let send = socket( - AddressFamily::Inet6, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .expect("send socket failed"); - sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa)) - .expect("sendmsg failed"); - } - - { - let mut buf = [0u8; 8]; - let mut iovec = [IoSliceMut::new(&mut buf)]; - let mut space = cmsg_space!(libc::sockaddr_in6); - let msg = recvmsg::<()>( - receive, - &mut iovec, - Some(&mut space), - MsgFlags::empty(), - ) - .expect("recvmsg failed"); - assert!(!msg - .flags - .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); - assert_eq!(msg.cmsgs().count(), 1, "expected 1 cmsgs"); - - let mut rx_recvorigdstaddr = false; - for cmsg in msg.cmsgs() { - match cmsg { - ControlMessageOwned::Ipv6OrigDstAddr(addr) => { - rx_recvorigdstaddr = true; - if let Some(sin) = lo.as_sockaddr_in6() { - assert_eq!(sin.as_ref().sin6_addr.s6_addr, - addr.sin6_addr.s6_addr, - "unexpected destination address (expected {:?}, got {:?})", - sin.as_ref().sin6_addr.s6_addr, - addr.sin6_addr.s6_addr); - } else { - panic!("unexpected Sockaddr"); - } - } - _ => panic!("unexpected additional control msg"), - } - } - assert!(rx_recvorigdstaddr); - assert_eq!(msg.bytes, 8); - assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]); - } -} - -#[cfg(any( - target_os = "android", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", -))] -// qemu doesn't seem to be emulating this correctly in these architectures -#[cfg_attr( - all( - qemu, - any( - target_arch = "mips", - target_arch = "mips64", - target_arch = "powerpc64", - ) - ), - ignore -)] -#[test] -pub fn test_recv_ipv6pktinfo() { - use nix::net::if_::*; - use nix::sys::socket::sockopt::Ipv6RecvPacketInfo; - use nix::sys::socket::{bind, SockFlag, SockType, SockaddrIn6}; - use nix::sys::socket::{getsockname, setsockopt, socket}; - use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags}; - use std::io::{IoSlice, IoSliceMut}; - - let lo_ifaddr = loopback_address(AddressFamily::Inet6); - let (lo_name, lo) = match lo_ifaddr { - Some(ifaddr) => ( - ifaddr.interface_name, - ifaddr.address.expect("Expect IPv6 address on interface"), - ), - None => return, - }; - let receive = socket( - AddressFamily::Inet6, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .expect("receive socket failed"); - bind(receive, &lo).expect("bind failed"); - let sa: SockaddrIn6 = getsockname(receive).expect("getsockname failed"); - setsockopt(receive, Ipv6RecvPacketInfo, &true).expect("setsockopt failed"); - - { - let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; - let iov = [IoSlice::new(&slice)]; - - let send = socket( - AddressFamily::Inet6, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .expect("send socket failed"); - sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa)) - .expect("sendmsg failed"); - } - - { - let mut buf = [0u8; 8]; - let mut iovec = [IoSliceMut::new(&mut buf)]; - - let mut space = cmsg_space!(libc::in6_pktinfo); - let msg = recvmsg::<()>( - receive, - &mut iovec, - Some(&mut space), - MsgFlags::empty(), - ) - .expect("recvmsg failed"); - assert!(!msg - .flags - .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); - - let mut cmsgs = msg.cmsgs(); - if let Some(ControlMessageOwned::Ipv6PacketInfo(pktinfo)) = cmsgs.next() - { - let i = if_nametoindex(lo_name.as_bytes()).expect("if_nametoindex"); - assert_eq!( - pktinfo.ipi6_ifindex as libc::c_uint, i, - "unexpected ifindex (expected {}, got {})", - i, pktinfo.ipi6_ifindex - ); - } - assert!(cmsgs.next().is_none(), "unexpected additional control msg"); - assert_eq!(msg.bytes, 8); - assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]); - } -} - -#[cfg(any(target_os = "android", target_os = "linux"))] -#[cfg_attr(graviton, ignore = "Not supported by the CI environment")] -#[test] -pub fn test_vsock() { - use nix::errno::Errno; - use nix::sys::socket::{ - bind, connect, listen, socket, AddressFamily, SockFlag, SockType, - VsockAddr, - }; - use nix::unistd::close; - use std::thread; - - let port: u32 = 3000; - - let s1 = socket( - AddressFamily::Vsock, - SockType::Stream, - SockFlag::empty(), - None, - ) - .expect("socket failed"); - - // VMADDR_CID_HYPERVISOR is reserved, so we expect an EADDRNOTAVAIL error. - let sockaddr_hv = VsockAddr::new(libc::VMADDR_CID_HYPERVISOR, port); - assert_eq!(bind(s1, &sockaddr_hv).err(), Some(Errno::EADDRNOTAVAIL)); - - let sockaddr_any = VsockAddr::new(libc::VMADDR_CID_ANY, port); - assert_eq!(bind(s1, &sockaddr_any), Ok(())); - listen(s1, 10).expect("listen failed"); - - let thr = thread::spawn(move || { - let cid: u32 = libc::VMADDR_CID_HOST; - - let s2 = socket( - AddressFamily::Vsock, - SockType::Stream, - SockFlag::empty(), - None, - ) - .expect("socket failed"); - - let sockaddr_host = VsockAddr::new(cid, port); - - // The current implementation does not support loopback devices, so, - // for now, we expect a failure on the connect. - assert_ne!(connect(s2, &sockaddr_host), Ok(())); - - close(s2).unwrap(); - }); - - close(s1).unwrap(); - thr.join().unwrap(); -} - -// Disable the test on emulated platforms because it fails in Cirrus-CI. Lack -// of QEMU support is suspected. -#[cfg_attr(qemu, ignore)] -#[cfg(all(target_os = "linux"))] -#[test] -fn test_recvmsg_timestampns() { - use nix::sys::socket::*; - use nix::sys::time::*; - use std::io::{IoSlice, IoSliceMut}; - use std::time::*; - - // Set up - let message = "Ohayō!".as_bytes(); - let in_socket = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .unwrap(); - setsockopt(in_socket, sockopt::ReceiveTimestampns, &true).unwrap(); - let localhost = SockaddrIn::new(127, 0, 0, 1, 0); - bind(in_socket, &localhost).unwrap(); - let address: SockaddrIn = getsockname(in_socket).unwrap(); - // Get initial time - let time0 = SystemTime::now(); - // Send the message - let iov = [IoSlice::new(message)]; - let flags = MsgFlags::empty(); - let l = sendmsg(in_socket, &iov, &[], flags, Some(&address)).unwrap(); - assert_eq!(message.len(), l); - // Receive the message - let mut buffer = vec![0u8; message.len()]; - let mut cmsgspace = nix::cmsg_space!(TimeSpec); - - let mut iov = [IoSliceMut::new(&mut buffer)]; - let r = recvmsg::<()>(in_socket, &mut iov, Some(&mut cmsgspace), flags) - .unwrap(); - let rtime = match r.cmsgs().next() { - Some(ControlMessageOwned::ScmTimestampns(rtime)) => rtime, - Some(_) => panic!("Unexpected control message"), - None => panic!("No control message"), - }; - // Check the final time - let time1 = SystemTime::now(); - // the packet's received timestamp should lie in-between the two system - // times, unless the system clock was adjusted in the meantime. - let rduration = - Duration::new(rtime.tv_sec() as u64, rtime.tv_nsec() as u32); - assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration); - assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap()); - // Close socket - nix::unistd::close(in_socket).unwrap(); -} - -// Disable the test on emulated platforms because it fails in Cirrus-CI. Lack -// of QEMU support is suspected. -#[cfg_attr(qemu, ignore)] -#[cfg(all(target_os = "linux"))] -#[test] -fn test_recvmmsg_timestampns() { - use nix::sys::socket::*; - use nix::sys::time::*; - use std::io::{IoSlice, IoSliceMut}; - use std::time::*; - - // Set up - let message = "Ohayō!".as_bytes(); - let in_socket = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .unwrap(); - setsockopt(in_socket, sockopt::ReceiveTimestampns, &true).unwrap(); - let localhost = SockaddrIn::from_str("127.0.0.1:0").unwrap(); - bind(in_socket, &localhost).unwrap(); - let address: SockaddrIn = getsockname(in_socket).unwrap(); - // Get initial time - let time0 = SystemTime::now(); - // Send the message - let iov = [IoSlice::new(message)]; - let flags = MsgFlags::empty(); - let l = sendmsg(in_socket, &iov, &[], flags, Some(&address)).unwrap(); - assert_eq!(message.len(), l); - // Receive the message - let mut buffer = vec![0u8; message.len()]; - let cmsgspace = nix::cmsg_space!(TimeSpec); - let iov = vec![[IoSliceMut::new(&mut buffer)]]; - let mut data = MultiHeaders::preallocate(1, Some(cmsgspace)); - let r: Vec<RecvMsg<()>> = - recvmmsg(in_socket, &mut data, iov.iter(), flags, None) - .unwrap() - .collect(); - let rtime = match r[0].cmsgs().next() { - Some(ControlMessageOwned::ScmTimestampns(rtime)) => rtime, - Some(_) => panic!("Unexpected control message"), - None => panic!("No control message"), - }; - // Check the final time - let time1 = SystemTime::now(); - // the packet's received timestamp should lie in-between the two system - // times, unless the system clock was adjusted in the meantime. - let rduration = - Duration::new(rtime.tv_sec() as u64, rtime.tv_nsec() as u32); - assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration); - assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap()); - // Close socket - nix::unistd::close(in_socket).unwrap(); -} - -// Disable the test on emulated platforms because it fails in Cirrus-CI. Lack -// of QEMU support is suspected. -#[cfg_attr(qemu, ignore)] -#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] -#[test] -fn test_recvmsg_rxq_ovfl() { - use nix::sys::socket::sockopt::{RcvBuf, RxqOvfl}; - use nix::sys::socket::*; - use nix::Error; - use std::io::{IoSlice, IoSliceMut}; - - let message = [0u8; 2048]; - let bufsize = message.len() * 2; - - let in_socket = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .unwrap(); - let out_socket = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .unwrap(); - - let localhost = SockaddrIn::from_str("127.0.0.1:0").unwrap(); - bind(in_socket, &localhost).unwrap(); - - let address: SockaddrIn = getsockname(in_socket).unwrap(); - connect(out_socket, &address).unwrap(); - - // Set SO_RXQ_OVFL flag. - setsockopt(in_socket, RxqOvfl, &1).unwrap(); - - // Set the receiver buffer size to hold only 2 messages. - setsockopt(in_socket, RcvBuf, &bufsize).unwrap(); - - let mut drop_counter = 0; - - for _ in 0..2 { - let iov = [IoSlice::new(&message)]; - let flags = MsgFlags::empty(); - - // Send the 3 messages (the receiver buffer can only hold 2 messages) - // to create an overflow. - for _ in 0..3 { - let l = - sendmsg(out_socket, &iov, &[], flags, Some(&address)).unwrap(); - assert_eq!(message.len(), l); - } - - // Receive the message and check the drop counter if any. - loop { - let mut buffer = vec![0u8; message.len()]; - let mut cmsgspace = nix::cmsg_space!(u32); - - let mut iov = [IoSliceMut::new(&mut buffer)]; - - match recvmsg::<()>( - in_socket, - &mut iov, - Some(&mut cmsgspace), - MsgFlags::MSG_DONTWAIT, - ) { - Ok(r) => { - drop_counter = match r.cmsgs().next() { - Some(ControlMessageOwned::RxqOvfl(drop_counter)) => { - drop_counter - } - Some(_) => panic!("Unexpected control message"), - None => 0, - }; - } - Err(Error::EAGAIN) => { - break; - } - _ => { - panic!("unknown recvmsg() error"); - } - } - } - } - - // One packet lost. - assert_eq!(drop_counter, 1); - - // Close sockets - nix::unistd::close(in_socket).unwrap(); - nix::unistd::close(out_socket).unwrap(); -} - -#[cfg(any(target_os = "linux", target_os = "android",))] -mod linux_errqueue { - use super::FromStr; - use nix::sys::socket::*; - - // Send a UDP datagram to a bogus destination address and observe an ICMP error (v4). - // - // Disable the test on QEMU because QEMU emulation of IP_RECVERR is broken (as documented on PR - // #1514). - #[cfg_attr(qemu, ignore)] - #[test] - fn test_recverr_v4() { - #[repr(u8)] - enum IcmpTypes { - DestUnreach = 3, // ICMP_DEST_UNREACH - } - #[repr(u8)] - enum IcmpUnreachCodes { - PortUnreach = 3, // ICMP_PORT_UNREACH - } - - test_recverr_impl::<sockaddr_in, _, _>( - "127.0.0.1:6800", - AddressFamily::Inet, - sockopt::Ipv4RecvErr, - libc::SO_EE_ORIGIN_ICMP, - IcmpTypes::DestUnreach as u8, - IcmpUnreachCodes::PortUnreach as u8, - // Closure handles protocol-specific testing and returns generic sock_extended_err for - // protocol-independent test impl. - |cmsg| { - if let ControlMessageOwned::Ipv4RecvErr(ext_err, err_addr) = - cmsg - { - if let Some(origin) = err_addr { - // Validate that our network error originated from 127.0.0.1:0. - assert_eq!(origin.sin_family, AddressFamily::Inet as _); - assert_eq!( - origin.sin_addr.s_addr, - u32::from_be(0x7f000001) - ); - assert_eq!(origin.sin_port, 0); - } else { - panic!("Expected some error origin"); - } - *ext_err - } else { - panic!("Unexpected control message {:?}", cmsg); - } - }, - ) - } - - // Essentially the same test as v4. - // - // Disable the test on QEMU because QEMU emulation of IPV6_RECVERR is broken (as documented on - // PR #1514). - #[cfg_attr(qemu, ignore)] - #[test] - fn test_recverr_v6() { - #[repr(u8)] - enum IcmpV6Types { - DestUnreach = 1, // ICMPV6_DEST_UNREACH - } - #[repr(u8)] - enum IcmpV6UnreachCodes { - PortUnreach = 4, // ICMPV6_PORT_UNREACH - } - - test_recverr_impl::<sockaddr_in6, _, _>( - "[::1]:6801", - AddressFamily::Inet6, - sockopt::Ipv6RecvErr, - libc::SO_EE_ORIGIN_ICMP6, - IcmpV6Types::DestUnreach as u8, - IcmpV6UnreachCodes::PortUnreach as u8, - // Closure handles protocol-specific testing and returns generic sock_extended_err for - // protocol-independent test impl. - |cmsg| { - if let ControlMessageOwned::Ipv6RecvErr(ext_err, err_addr) = - cmsg - { - if let Some(origin) = err_addr { - // Validate that our network error originated from localhost:0. - assert_eq!( - origin.sin6_family, - AddressFamily::Inet6 as _ - ); - assert_eq!( - origin.sin6_addr.s6_addr, - std::net::Ipv6Addr::LOCALHOST.octets() - ); - assert_eq!(origin.sin6_port, 0); - } else { - panic!("Expected some error origin"); - } - *ext_err - } else { - panic!("Unexpected control message {:?}", cmsg); - } - }, - ) - } - - fn test_recverr_impl<SA, OPT, TESTF>( - sa: &str, - af: AddressFamily, - opt: OPT, - ee_origin: u8, - ee_type: u8, - ee_code: u8, - testf: TESTF, - ) where - OPT: SetSockOpt<Val = bool>, - TESTF: FnOnce(&ControlMessageOwned) -> libc::sock_extended_err, - { - use nix::errno::Errno; - use std::io::IoSliceMut; - - const MESSAGE_CONTENTS: &str = "ABCDEF"; - let std_sa = std::net::SocketAddr::from_str(sa).unwrap(); - let sock_addr = SockaddrStorage::from(std_sa); - let sock = socket(af, SockType::Datagram, SockFlag::SOCK_CLOEXEC, None) - .unwrap(); - setsockopt(sock, opt, &true).unwrap(); - if let Err(e) = sendto( - sock, - MESSAGE_CONTENTS.as_bytes(), - &sock_addr, - MsgFlags::empty(), - ) { - assert_eq!(e, Errno::EADDRNOTAVAIL); - println!("{:?} not available, skipping test.", af); - return; - } - - let mut buf = [0u8; 8]; - let mut iovec = [IoSliceMut::new(&mut buf)]; - let mut cspace = cmsg_space!(libc::sock_extended_err, SA); - - let msg = recvmsg( - sock, - &mut iovec, - Some(&mut cspace), - MsgFlags::MSG_ERRQUEUE, - ) - .unwrap(); - // The sent message / destination associated with the error is returned: - assert_eq!(msg.bytes, MESSAGE_CONTENTS.as_bytes().len()); - // recvmsg(2): "The original destination address of the datagram that caused the error is - // supplied via msg_name;" however, this is not literally true. E.g., an earlier version - // of this test used 0.0.0.0 (::0) as the destination address, which was mutated into - // 127.0.0.1 (::1). - assert_eq!(msg.address, Some(sock_addr)); - - // Check for expected control message. - let ext_err = match msg.cmsgs().next() { - Some(cmsg) => testf(&cmsg), - None => panic!("No control message"), - }; - - assert_eq!(ext_err.ee_errno, libc::ECONNREFUSED as u32); - assert_eq!(ext_err.ee_origin, ee_origin); - // ip(7): ee_type and ee_code are set from the type and code fields of the ICMP (ICMPv6) - // header. - assert_eq!(ext_err.ee_type, ee_type); - assert_eq!(ext_err.ee_code, ee_code); - // ip(7): ee_info contains the discovered MTU for EMSGSIZE errors. - assert_eq!(ext_err.ee_info, 0); - - let bytes = msg.bytes; - assert_eq!(&buf[..bytes], MESSAGE_CONTENTS.as_bytes()); - } -} - -// Disable the test on emulated platforms because it fails in Cirrus-CI. Lack -// of QEMU support is suspected. -#[cfg_attr(qemu, ignore)] -#[cfg(target_os = "linux")] -#[test] -pub fn test_txtime() { - use nix::sys::socket::{ - bind, recvmsg, sendmsg, setsockopt, socket, sockopt, ControlMessage, - MsgFlags, SockFlag, SockType, SockaddrIn, - }; - use nix::sys::time::TimeValLike; - use nix::time::{clock_gettime, ClockId}; - - require_kernel_version!(test_txtime, ">= 5.8"); - - let sock_addr = SockaddrIn::from_str("127.0.0.1:6802").unwrap(); - - let ssock = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .expect("send socket failed"); - - let txtime_cfg = libc::sock_txtime { - clockid: libc::CLOCK_MONOTONIC, - flags: 0, - }; - setsockopt(ssock, sockopt::TxTime, &txtime_cfg).unwrap(); - - let rsock = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .unwrap(); - bind(rsock, &sock_addr).unwrap(); - - let sbuf = [0u8; 2048]; - let iov1 = [std::io::IoSlice::new(&sbuf)]; - - let now = clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap(); - let delay = std::time::Duration::from_secs(1).into(); - let txtime = (now + delay).num_nanoseconds() as u64; - - let cmsg = ControlMessage::TxTime(&txtime); - sendmsg(ssock, &iov1, &[cmsg], MsgFlags::empty(), Some(&sock_addr)) - .unwrap(); - - let mut rbuf = [0u8; 2048]; - let mut iov2 = [std::io::IoSliceMut::new(&mut rbuf)]; - recvmsg::<()>(rsock, &mut iov2, None, MsgFlags::empty()).unwrap(); -} diff --git a/vendor/nix/test/sys/test_sockopt.rs b/vendor/nix/test/sys/test_sockopt.rs deleted file mode 100644 index 34bef945e..000000000 --- a/vendor/nix/test/sys/test_sockopt.rs +++ /dev/null @@ -1,431 +0,0 @@ -#[cfg(any(target_os = "android", target_os = "linux"))] -use crate::*; -use nix::sys::socket::{ - getsockopt, setsockopt, socket, sockopt, AddressFamily, SockFlag, - SockProtocol, SockType, -}; -use rand::{thread_rng, Rng}; - -// NB: FreeBSD supports LOCAL_PEERCRED for SOCK_SEQPACKET, but OSX does not. -#[cfg(any(target_os = "dragonfly", target_os = "freebsd",))] -#[test] -pub fn test_local_peercred_seqpacket() { - use nix::{ - sys::socket::socketpair, - unistd::{Gid, Uid}, - }; - - let (fd1, _fd2) = socketpair( - AddressFamily::Unix, - SockType::SeqPacket, - None, - SockFlag::empty(), - ) - .unwrap(); - let xucred = getsockopt(fd1, sockopt::LocalPeerCred).unwrap(); - assert_eq!(xucred.version(), 0); - assert_eq!(Uid::from_raw(xucred.uid()), Uid::current()); - assert_eq!(Gid::from_raw(xucred.groups()[0]), Gid::current()); -} - -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "ios" -))] -#[test] -pub fn test_local_peercred_stream() { - use nix::{ - sys::socket::socketpair, - unistd::{Gid, Uid}, - }; - - let (fd1, _fd2) = socketpair( - AddressFamily::Unix, - SockType::Stream, - None, - SockFlag::empty(), - ) - .unwrap(); - let xucred = getsockopt(fd1, sockopt::LocalPeerCred).unwrap(); - assert_eq!(xucred.version(), 0); - assert_eq!(Uid::from_raw(xucred.uid()), Uid::current()); - assert_eq!(Gid::from_raw(xucred.groups()[0]), Gid::current()); -} - -#[cfg(target_os = "linux")] -#[test] -fn is_so_mark_functional() { - use nix::sys::socket::sockopt; - - require_capability!("is_so_mark_functional", CAP_NET_ADMIN); - - let s = socket( - AddressFamily::Inet, - SockType::Stream, - SockFlag::empty(), - None, - ) - .unwrap(); - setsockopt(s, sockopt::Mark, &1337).unwrap(); - let mark = getsockopt(s, sockopt::Mark).unwrap(); - assert_eq!(mark, 1337); -} - -#[test] -fn test_so_buf() { - let fd = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - SockProtocol::Udp, - ) - .unwrap(); - let bufsize: usize = thread_rng().gen_range(4096..131_072); - setsockopt(fd, sockopt::SndBuf, &bufsize).unwrap(); - let actual = getsockopt(fd, sockopt::SndBuf).unwrap(); - assert!(actual >= bufsize); - setsockopt(fd, sockopt::RcvBuf, &bufsize).unwrap(); - let actual = getsockopt(fd, sockopt::RcvBuf).unwrap(); - assert!(actual >= bufsize); -} - -#[test] -fn test_so_tcp_maxseg() { - use nix::sys::socket::{accept, bind, connect, listen, SockaddrIn}; - use nix::unistd::{close, write}; - use std::net::SocketAddrV4; - use std::str::FromStr; - - let std_sa = SocketAddrV4::from_str("127.0.0.1:4001").unwrap(); - let sock_addr = SockaddrIn::from(std_sa); - - let rsock = socket( - AddressFamily::Inet, - SockType::Stream, - SockFlag::empty(), - SockProtocol::Tcp, - ) - .unwrap(); - bind(rsock, &sock_addr).unwrap(); - listen(rsock, 10).unwrap(); - let initial = getsockopt(rsock, sockopt::TcpMaxSeg).unwrap(); - // Initial MSS is expected to be 536 (https://tools.ietf.org/html/rfc879#section-1) but some - // platforms keep it even lower. This might fail if you've tuned your initial MSS to be larger - // than 700 - cfg_if! { - if #[cfg(any(target_os = "android", target_os = "linux"))] { - let segsize: u32 = 873; - assert!(initial < segsize); - setsockopt(rsock, sockopt::TcpMaxSeg, &segsize).unwrap(); - } else { - assert!(initial < 700); - } - } - - // Connect and check the MSS that was advertised - let ssock = socket( - AddressFamily::Inet, - SockType::Stream, - SockFlag::empty(), - SockProtocol::Tcp, - ) - .unwrap(); - connect(ssock, &sock_addr).unwrap(); - let rsess = accept(rsock).unwrap(); - write(rsess, b"hello").unwrap(); - let actual = getsockopt(ssock, sockopt::TcpMaxSeg).unwrap(); - // Actual max segment size takes header lengths into account, max IPv4 options (60 bytes) + max - // TCP options (40 bytes) are subtracted from the requested maximum as a lower boundary. - cfg_if! { - if #[cfg(any(target_os = "android", target_os = "linux"))] { - assert!((segsize - 100) <= actual); - assert!(actual <= segsize); - } else { - assert!(initial < actual); - assert!(536 < actual); - } - } - close(rsock).unwrap(); - close(ssock).unwrap(); -} - -#[test] -fn test_so_type() { - let sockfd = socket( - AddressFamily::Inet, - SockType::Stream, - SockFlag::empty(), - None, - ) - .unwrap(); - - assert_eq!(Ok(SockType::Stream), getsockopt(sockfd, sockopt::SockType)); -} - -/// getsockopt(_, sockopt::SockType) should gracefully handle unknown socket -/// types. Regression test for https://github.com/nix-rust/nix/issues/1819 -#[cfg(any(target_os = "android", target_os = "linux",))] -#[test] -fn test_so_type_unknown() { - use nix::errno::Errno; - - require_capability!("test_so_type", CAP_NET_RAW); - let sockfd = unsafe { libc::socket(libc::AF_PACKET, libc::SOCK_PACKET, 0) }; - assert!(sockfd >= 0, "Error opening socket: {}", nix::Error::last()); - - assert_eq!(Err(Errno::EINVAL), getsockopt(sockfd, sockopt::SockType)); -} - -// The CI doesn't supported getsockopt and setsockopt on emulated processors. -// It's believed that a QEMU issue, the tests run ok on a fully emulated system. -// Current CI just run the binary with QEMU but the Kernel remains the same as the host. -// So the syscall doesn't work properly unless the kernel is also emulated. -#[test] -#[cfg(all( - any(target_arch = "x86", target_arch = "x86_64"), - any(target_os = "freebsd", target_os = "linux") -))] -fn test_tcp_congestion() { - use std::ffi::OsString; - - let fd = socket( - AddressFamily::Inet, - SockType::Stream, - SockFlag::empty(), - None, - ) - .unwrap(); - - let val = getsockopt(fd, sockopt::TcpCongestion).unwrap(); - setsockopt(fd, sockopt::TcpCongestion, &val).unwrap(); - - setsockopt( - fd, - sockopt::TcpCongestion, - &OsString::from("tcp_congestion_does_not_exist"), - ) - .unwrap_err(); - - assert_eq!(getsockopt(fd, sockopt::TcpCongestion).unwrap(), val); -} - -#[test] -#[cfg(any(target_os = "android", target_os = "linux"))] -fn test_bindtodevice() { - skip_if_not_root!("test_bindtodevice"); - - let fd = socket( - AddressFamily::Inet, - SockType::Stream, - SockFlag::empty(), - None, - ) - .unwrap(); - - let val = getsockopt(fd, sockopt::BindToDevice).unwrap(); - setsockopt(fd, sockopt::BindToDevice, &val).unwrap(); - - assert_eq!(getsockopt(fd, sockopt::BindToDevice).unwrap(), val); -} - -#[test] -fn test_so_tcp_keepalive() { - let fd = socket( - AddressFamily::Inet, - SockType::Stream, - SockFlag::empty(), - SockProtocol::Tcp, - ) - .unwrap(); - setsockopt(fd, sockopt::KeepAlive, &true).unwrap(); - assert!(getsockopt(fd, sockopt::KeepAlive).unwrap()); - - #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux" - ))] - { - let x = getsockopt(fd, sockopt::TcpKeepIdle).unwrap(); - setsockopt(fd, sockopt::TcpKeepIdle, &(x + 1)).unwrap(); - assert_eq!(getsockopt(fd, sockopt::TcpKeepIdle).unwrap(), x + 1); - - let x = getsockopt(fd, sockopt::TcpKeepCount).unwrap(); - setsockopt(fd, sockopt::TcpKeepCount, &(x + 1)).unwrap(); - assert_eq!(getsockopt(fd, sockopt::TcpKeepCount).unwrap(), x + 1); - - let x = getsockopt(fd, sockopt::TcpKeepInterval).unwrap(); - setsockopt(fd, sockopt::TcpKeepInterval, &(x + 1)).unwrap(); - assert_eq!(getsockopt(fd, sockopt::TcpKeepInterval).unwrap(), x + 1); - } -} - -#[test] -#[cfg(any(target_os = "android", target_os = "linux"))] -#[cfg_attr(qemu, ignore)] -fn test_get_mtu() { - use nix::sys::socket::{bind, connect, SockaddrIn}; - use std::net::SocketAddrV4; - use std::str::FromStr; - - let std_sa = SocketAddrV4::from_str("127.0.0.1:4001").unwrap(); - let std_sb = SocketAddrV4::from_str("127.0.0.1:4002").unwrap(); - - let usock = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - SockProtocol::Udp, - ) - .unwrap(); - - // Bind and initiate connection - bind(usock, &SockaddrIn::from(std_sa)).unwrap(); - connect(usock, &SockaddrIn::from(std_sb)).unwrap(); - - // Loopback connections have 2^16 - the maximum - MTU - assert_eq!(getsockopt(usock, sockopt::IpMtu), Ok(u16::MAX as i32)) -} - -#[test] -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] -fn test_ttl_opts() { - let fd4 = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .unwrap(); - setsockopt(fd4, sockopt::Ipv4Ttl, &1) - .expect("setting ipv4ttl on an inet socket should succeed"); - let fd6 = socket( - AddressFamily::Inet6, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .unwrap(); - setsockopt(fd6, sockopt::Ipv6Ttl, &1) - .expect("setting ipv6ttl on an inet6 socket should succeed"); -} - -#[test] -#[cfg(any(target_os = "ios", target_os = "macos"))] -fn test_dontfrag_opts() { - let fd4 = socket( - AddressFamily::Inet, - SockType::Stream, - SockFlag::empty(), - SockProtocol::Tcp, - ) - .unwrap(); - setsockopt(fd4, sockopt::IpDontFrag, &true) - .expect("setting IP_DONTFRAG on an inet stream socket should succeed"); - setsockopt(fd4, sockopt::IpDontFrag, &false).expect( - "unsetting IP_DONTFRAG on an inet stream socket should succeed", - ); - let fd4d = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .unwrap(); - setsockopt(fd4d, sockopt::IpDontFrag, &true).expect( - "setting IP_DONTFRAG on an inet datagram socket should succeed", - ); - setsockopt(fd4d, sockopt::IpDontFrag, &false).expect( - "unsetting IP_DONTFRAG on an inet datagram socket should succeed", - ); -} - -#[test] -#[cfg(any( - target_os = "android", - target_os = "ios", - target_os = "linux", - target_os = "macos", -))] -// Disable the test under emulation because it fails in Cirrus-CI. Lack -// of QEMU support is suspected. -#[cfg_attr(qemu, ignore)] -fn test_v6dontfrag_opts() { - let fd6 = socket( - AddressFamily::Inet6, - SockType::Stream, - SockFlag::empty(), - SockProtocol::Tcp, - ) - .unwrap(); - setsockopt(fd6, sockopt::Ipv6DontFrag, &true).expect( - "setting IPV6_DONTFRAG on an inet6 stream socket should succeed", - ); - setsockopt(fd6, sockopt::Ipv6DontFrag, &false).expect( - "unsetting IPV6_DONTFRAG on an inet6 stream socket should succeed", - ); - let fd6d = socket( - AddressFamily::Inet6, - SockType::Datagram, - SockFlag::empty(), - None, - ) - .unwrap(); - setsockopt(fd6d, sockopt::Ipv6DontFrag, &true).expect( - "setting IPV6_DONTFRAG on an inet6 datagram socket should succeed", - ); - setsockopt(fd6d, sockopt::Ipv6DontFrag, &false).expect( - "unsetting IPV6_DONTFRAG on an inet6 datagram socket should succeed", - ); -} - -#[test] -#[cfg(target_os = "linux")] -fn test_so_priority() { - let fd = socket( - AddressFamily::Inet, - SockType::Stream, - SockFlag::empty(), - SockProtocol::Tcp, - ) - .unwrap(); - let priority = 3; - setsockopt(fd, sockopt::Priority, &priority).unwrap(); - assert_eq!(getsockopt(fd, sockopt::Priority).unwrap(), priority); -} - -#[test] -#[cfg(target_os = "linux")] -fn test_ip_tos() { - let fd = socket( - AddressFamily::Inet, - SockType::Stream, - SockFlag::empty(), - SockProtocol::Tcp, - ) - .unwrap(); - let tos = 0x80; // CS4 - setsockopt(fd, sockopt::IpTos, &tos).unwrap(); - assert_eq!(getsockopt(fd, sockopt::IpTos).unwrap(), tos); -} - -#[test] -#[cfg(target_os = "linux")] -// Disable the test under emulation because it fails in Cirrus-CI. Lack -// of QEMU support is suspected. -#[cfg_attr(qemu, ignore)] -fn test_ipv6_tclass() { - let fd = socket( - AddressFamily::Inet6, - SockType::Stream, - SockFlag::empty(), - SockProtocol::Tcp, - ) - .unwrap(); - let class = 0x80; // CS4 - setsockopt(fd, sockopt::Ipv6TClass, &class).unwrap(); - assert_eq!(getsockopt(fd, sockopt::Ipv6TClass).unwrap(), class); -} diff --git a/vendor/nix/test/sys/test_stat.rs b/vendor/nix/test/sys/test_stat.rs deleted file mode 100644 index 426b4b658..000000000 --- a/vendor/nix/test/sys/test_stat.rs +++ /dev/null @@ -1,29 +0,0 @@ -// The conversion is not useless on all platforms. -#[allow(clippy::useless_conversion)] -#[cfg(target_os = "freebsd")] -#[test] -fn test_chflags() { - use nix::{ - sys::stat::{fstat, FileFlag}, - unistd::chflags, - }; - use std::os::unix::io::AsRawFd; - use tempfile::NamedTempFile; - - let f = NamedTempFile::new().unwrap(); - - let initial = FileFlag::from_bits_truncate( - fstat(f.as_raw_fd()).unwrap().st_flags.into(), - ); - // UF_OFFLINE is preserved by all FreeBSD file systems, but not interpreted - // in any way, so it's handy for testing. - let commanded = initial ^ FileFlag::UF_OFFLINE; - - chflags(f.path(), commanded).unwrap(); - - let changed = FileFlag::from_bits_truncate( - fstat(f.as_raw_fd()).unwrap().st_flags.into(), - ); - - assert_eq!(commanded, changed); -} diff --git a/vendor/nix/test/sys/test_sysinfo.rs b/vendor/nix/test/sys/test_sysinfo.rs deleted file mode 100644 index 2897366ef..000000000 --- a/vendor/nix/test/sys/test_sysinfo.rs +++ /dev/null @@ -1,20 +0,0 @@ -use nix::sys::sysinfo::*; - -#[test] -fn sysinfo_works() { - let info = sysinfo().unwrap(); - - let (l1, l5, l15) = info.load_average(); - assert!(l1 >= 0.0); - assert!(l5 >= 0.0); - assert!(l15 >= 0.0); - - info.uptime(); // just test Duration construction - - assert!( - info.swap_free() <= info.swap_total(), - "more swap available than installed (free: {}, total: {})", - info.swap_free(), - info.swap_total() - ); -} diff --git a/vendor/nix/test/sys/test_termios.rs b/vendor/nix/test/sys/test_termios.rs deleted file mode 100644 index aaf00084f..000000000 --- a/vendor/nix/test/sys/test_termios.rs +++ /dev/null @@ -1,136 +0,0 @@ -use std::os::unix::prelude::*; -use tempfile::tempfile; - -use nix::errno::Errno; -use nix::fcntl; -use nix::pty::openpty; -use nix::sys::termios::{self, tcgetattr, LocalFlags, OutputFlags}; -use nix::unistd::{close, read, write}; - -/// Helper function analogous to `std::io::Write::write_all`, but for `RawFd`s -fn write_all(f: RawFd, buf: &[u8]) { - let mut len = 0; - while len < buf.len() { - len += write(f, &buf[len..]).unwrap(); - } -} - -// Test tcgetattr on a terminal -#[test] -fn test_tcgetattr_pty() { - // openpty uses ptname(3) internally - let _m = crate::PTSNAME_MTX.lock(); - - let pty = openpty(None, None).expect("openpty failed"); - termios::tcgetattr(pty.slave).unwrap(); - close(pty.master).expect("closing the master failed"); - close(pty.slave).expect("closing the slave failed"); -} - -// Test tcgetattr on something that isn't a terminal -#[test] -fn test_tcgetattr_enotty() { - let file = tempfile().unwrap(); - assert_eq!( - termios::tcgetattr(file.as_raw_fd()).err(), - Some(Errno::ENOTTY) - ); -} - -// Test tcgetattr on an invalid file descriptor -#[test] -fn test_tcgetattr_ebadf() { - assert_eq!(termios::tcgetattr(-1).err(), Some(Errno::EBADF)); -} - -// Test modifying output flags -#[test] -fn test_output_flags() { - // openpty uses ptname(3) internally - let _m = crate::PTSNAME_MTX.lock(); - - // Open one pty to get attributes for the second one - let mut termios = { - let pty = openpty(None, None).expect("openpty failed"); - assert!(pty.master > 0); - assert!(pty.slave > 0); - let termios = tcgetattr(pty.slave).expect("tcgetattr failed"); - close(pty.master).unwrap(); - close(pty.slave).unwrap(); - termios - }; - - // Make sure postprocessing '\r' isn't specified by default or this test is useless. - assert!(!termios - .output_flags - .contains(OutputFlags::OPOST | OutputFlags::OCRNL)); - - // Specify that '\r' characters should be transformed to '\n' - // OPOST is specified to enable post-processing - termios - .output_flags - .insert(OutputFlags::OPOST | OutputFlags::OCRNL); - - // Open a pty - let pty = openpty(None, &termios).unwrap(); - assert!(pty.master > 0); - assert!(pty.slave > 0); - - // Write into the master - let string = "foofoofoo\r"; - write_all(pty.master, string.as_bytes()); - - // Read from the slave verifying that the output has been properly transformed - let mut buf = [0u8; 10]; - crate::read_exact(pty.slave, &mut buf); - let transformed_string = "foofoofoo\n"; - close(pty.master).unwrap(); - close(pty.slave).unwrap(); - assert_eq!(&buf, transformed_string.as_bytes()); -} - -// Test modifying local flags -#[test] -fn test_local_flags() { - // openpty uses ptname(3) internally - let _m = crate::PTSNAME_MTX.lock(); - - // Open one pty to get attributes for the second one - let mut termios = { - let pty = openpty(None, None).unwrap(); - assert!(pty.master > 0); - assert!(pty.slave > 0); - let termios = tcgetattr(pty.slave).unwrap(); - close(pty.master).unwrap(); - close(pty.slave).unwrap(); - termios - }; - - // Make sure echo is specified by default or this test is useless. - assert!(termios.local_flags.contains(LocalFlags::ECHO)); - - // Disable local echo - termios.local_flags.remove(LocalFlags::ECHO); - - // Open a new pty with our modified termios settings - let pty = openpty(None, &termios).unwrap(); - assert!(pty.master > 0); - assert!(pty.slave > 0); - - // Set the master is in nonblocking mode or reading will never return. - let flags = fcntl::fcntl(pty.master, fcntl::F_GETFL).unwrap(); - let new_flags = - fcntl::OFlag::from_bits_truncate(flags) | fcntl::OFlag::O_NONBLOCK; - fcntl::fcntl(pty.master, fcntl::F_SETFL(new_flags)).unwrap(); - - // Write into the master - let string = "foofoofoo\r"; - write_all(pty.master, string.as_bytes()); - - // Try to read from the master, which should not have anything as echoing was disabled. - let mut buf = [0u8; 10]; - let read = read(pty.master, &mut buf).unwrap_err(); - close(pty.master).unwrap(); - close(pty.slave).unwrap(); - assert_eq!(read, Errno::EAGAIN); -} diff --git a/vendor/nix/test/sys/test_timerfd.rs b/vendor/nix/test/sys/test_timerfd.rs deleted file mode 100644 index 08e292106..000000000 --- a/vendor/nix/test/sys/test_timerfd.rs +++ /dev/null @@ -1,69 +0,0 @@ -use nix::sys::time::{TimeSpec, TimeValLike}; -use nix::sys::timerfd::{ - ClockId, Expiration, TimerFd, TimerFlags, TimerSetTimeFlags, -}; -use std::time::Instant; - -#[test] -pub fn test_timerfd_oneshot() { - let timer = - TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()).unwrap(); - - let before = Instant::now(); - - timer - .set( - Expiration::OneShot(TimeSpec::seconds(1)), - TimerSetTimeFlags::empty(), - ) - .unwrap(); - - timer.wait().unwrap(); - - let millis = before.elapsed().as_millis(); - assert!(millis > 900); -} - -#[test] -pub fn test_timerfd_interval() { - let timer = - TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()).unwrap(); - - let before = Instant::now(); - timer - .set( - Expiration::IntervalDelayed( - TimeSpec::seconds(1), - TimeSpec::seconds(2), - ), - TimerSetTimeFlags::empty(), - ) - .unwrap(); - - timer.wait().unwrap(); - - let start_delay = before.elapsed().as_millis(); - assert!(start_delay > 900); - - timer.wait().unwrap(); - - let interval_delay = before.elapsed().as_millis(); - assert!(interval_delay > 2900); -} - -#[test] -pub fn test_timerfd_unset() { - let timer = - TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()).unwrap(); - - timer - .set( - Expiration::OneShot(TimeSpec::seconds(1)), - TimerSetTimeFlags::empty(), - ) - .unwrap(); - - timer.unset().unwrap(); - - assert!(timer.get().unwrap().is_none()); -} diff --git a/vendor/nix/test/sys/test_uio.rs b/vendor/nix/test/sys/test_uio.rs deleted file mode 100644 index 0f4b8a656..000000000 --- a/vendor/nix/test/sys/test_uio.rs +++ /dev/null @@ -1,270 +0,0 @@ -use nix::sys::uio::*; -use nix::unistd::*; -use rand::distributions::Alphanumeric; -use rand::{thread_rng, Rng}; -use std::fs::OpenOptions; -use std::io::IoSlice; -use std::os::unix::io::AsRawFd; -use std::{cmp, iter}; - -#[cfg(not(target_os = "redox"))] -use std::io::IoSliceMut; - -use tempfile::tempdir; -#[cfg(not(target_os = "redox"))] -use tempfile::tempfile; - -#[test] -fn test_writev() { - let mut to_write = Vec::with_capacity(16 * 128); - for _ in 0..16 { - let s: String = thread_rng() - .sample_iter(&Alphanumeric) - .map(char::from) - .take(128) - .collect(); - let b = s.as_bytes(); - to_write.extend(b.iter().cloned()); - } - // Allocate and fill iovecs - let mut iovecs = Vec::new(); - let mut consumed = 0; - while consumed < to_write.len() { - let left = to_write.len() - consumed; - let slice_len = if left <= 64 { - left - } else { - thread_rng().gen_range(64..cmp::min(256, left)) - }; - let b = &to_write[consumed..consumed + slice_len]; - iovecs.push(IoSlice::new(b)); - consumed += slice_len; - } - let pipe_res = pipe(); - let (reader, writer) = pipe_res.expect("Couldn't create pipe"); - // FileDesc will close its filedesc (reader). - let mut read_buf: Vec<u8> = iter::repeat(0u8).take(128 * 16).collect(); - // Blocking io, should write all data. - let write_res = writev(writer, &iovecs); - let written = write_res.expect("couldn't write"); - // Check whether we written all data - assert_eq!(to_write.len(), written); - let read_res = read(reader, &mut read_buf[..]); - let read = read_res.expect("couldn't read"); - // Check we have read as much as we written - assert_eq!(read, written); - // Check equality of written and read data - assert_eq!(&to_write, &read_buf); - close(writer).expect("closed writer"); - close(reader).expect("closed reader"); -} - -#[test] -#[cfg(not(target_os = "redox"))] -fn test_readv() { - let s: String = thread_rng() - .sample_iter(&Alphanumeric) - .map(char::from) - .take(128) - .collect(); - let to_write = s.as_bytes().to_vec(); - let mut storage = Vec::new(); - let mut allocated = 0; - while allocated < to_write.len() { - let left = to_write.len() - allocated; - let vec_len = if left <= 64 { - left - } else { - thread_rng().gen_range(64..cmp::min(256, left)) - }; - let v: Vec<u8> = iter::repeat(0u8).take(vec_len).collect(); - storage.push(v); - allocated += vec_len; - } - let mut iovecs = Vec::with_capacity(storage.len()); - for v in &mut storage { - iovecs.push(IoSliceMut::new(&mut v[..])); - } - let (reader, writer) = pipe().expect("couldn't create pipe"); - // Blocking io, should write all data. - write(writer, &to_write).expect("write failed"); - let read = readv(reader, &mut iovecs[..]).expect("read failed"); - // Check whether we've read all data - assert_eq!(to_write.len(), read); - // Cccumulate data from iovecs - let mut read_buf = Vec::with_capacity(to_write.len()); - for iovec in &iovecs { - read_buf.extend(iovec.iter().cloned()); - } - // Check whether iovecs contain all written data - assert_eq!(read_buf.len(), to_write.len()); - // Check equality of written and read data - assert_eq!(&read_buf, &to_write); - close(reader).expect("couldn't close reader"); - close(writer).expect("couldn't close writer"); -} - -#[test] -#[cfg(not(target_os = "redox"))] -fn test_pwrite() { - use std::io::Read; - - let mut file = tempfile().unwrap(); - let buf = [1u8; 8]; - assert_eq!(Ok(8), pwrite(file.as_raw_fd(), &buf, 8)); - let mut file_content = Vec::new(); - file.read_to_end(&mut file_content).unwrap(); - let mut expected = vec![0u8; 8]; - expected.extend(vec![1; 8]); - assert_eq!(file_content, expected); -} - -#[test] -fn test_pread() { - use std::io::Write; - - let tempdir = tempdir().unwrap(); - - let path = tempdir.path().join("pread_test_file"); - let mut file = OpenOptions::new() - .write(true) - .read(true) - .create(true) - .truncate(true) - .open(path) - .unwrap(); - let file_content: Vec<u8> = (0..64).collect(); - file.write_all(&file_content).unwrap(); - - let mut buf = [0u8; 16]; - assert_eq!(Ok(16), pread(file.as_raw_fd(), &mut buf, 16)); - let expected: Vec<_> = (16..32).collect(); - assert_eq!(&buf[..], &expected[..]); -} - -#[test] -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] -fn test_pwritev() { - use std::io::Read; - - let to_write: Vec<u8> = (0..128).collect(); - let expected: Vec<u8> = [vec![0; 100], to_write.clone()].concat(); - - let iovecs = [ - IoSlice::new(&to_write[0..17]), - IoSlice::new(&to_write[17..64]), - IoSlice::new(&to_write[64..128]), - ]; - - let tempdir = tempdir().unwrap(); - - // pwritev them into a temporary file - let path = tempdir.path().join("pwritev_test_file"); - let mut file = OpenOptions::new() - .write(true) - .read(true) - .create(true) - .truncate(true) - .open(path) - .unwrap(); - - let written = pwritev(file.as_raw_fd(), &iovecs, 100).ok().unwrap(); - assert_eq!(written, to_write.len()); - - // Read the data back and make sure it matches - let mut contents = Vec::new(); - file.read_to_end(&mut contents).unwrap(); - assert_eq!(contents, expected); -} - -#[test] -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] -fn test_preadv() { - use std::io::Write; - - let to_write: Vec<u8> = (0..200).collect(); - let expected: Vec<u8> = (100..200).collect(); - - let tempdir = tempdir().unwrap(); - - let path = tempdir.path().join("preadv_test_file"); - - let mut file = OpenOptions::new() - .read(true) - .write(true) - .create(true) - .truncate(true) - .open(path) - .unwrap(); - file.write_all(&to_write).unwrap(); - - let mut buffers: Vec<Vec<u8>> = vec![vec![0; 24], vec![0; 1], vec![0; 75]]; - - { - // Borrow the buffers into IoVecs and preadv into them - let mut iovecs: Vec<_> = buffers - .iter_mut() - .map(|buf| IoSliceMut::new(&mut buf[..])) - .collect(); - assert_eq!(Ok(100), preadv(file.as_raw_fd(), &mut iovecs, 100)); - } - - let all = buffers.concat(); - assert_eq!(all, expected); -} - -#[test] -#[cfg(all(target_os = "linux", not(target_env = "uclibc")))] -// uclibc doesn't implement process_vm_readv -// qemu-user doesn't implement process_vm_readv/writev on most arches -#[cfg_attr(qemu, ignore)] -fn test_process_vm_readv() { - use crate::*; - use nix::sys::signal::*; - use nix::sys::wait::*; - use nix::unistd::ForkResult::*; - - require_capability!("test_process_vm_readv", CAP_SYS_PTRACE); - let _m = crate::FORK_MTX.lock(); - - // Pre-allocate memory in the child, since allocation isn't safe - // post-fork (~= async-signal-safe) - let mut vector = vec![1u8, 2, 3, 4, 5]; - - let (r, w) = pipe().unwrap(); - match unsafe { fork() }.expect("Error: Fork Failed") { - Parent { child } => { - close(w).unwrap(); - // wait for child - read(r, &mut [0u8]).unwrap(); - close(r).unwrap(); - - let ptr = vector.as_ptr() as usize; - let remote_iov = RemoteIoVec { base: ptr, len: 5 }; - let mut buf = vec![0u8; 5]; - - let ret = process_vm_readv( - child, - &mut [IoSliceMut::new(&mut buf)], - &[remote_iov], - ); - - kill(child, SIGTERM).unwrap(); - waitpid(child, None).unwrap(); - - assert_eq!(Ok(5), ret); - assert_eq!(20u8, buf.iter().sum()); - } - Child => { - let _ = close(r); - for i in &mut vector { - *i += 1; - } - let _ = write(w, b"\0"); - let _ = close(w); - loop { - pause(); - } - } - } -} diff --git a/vendor/nix/test/sys/test_wait.rs b/vendor/nix/test/sys/test_wait.rs deleted file mode 100644 index d472f1ec1..000000000 --- a/vendor/nix/test/sys/test_wait.rs +++ /dev/null @@ -1,257 +0,0 @@ -use libc::_exit; -use nix::errno::Errno; -use nix::sys::signal::*; -use nix::sys::wait::*; -use nix::unistd::ForkResult::*; -use nix::unistd::*; - -#[test] -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] -fn test_wait_signal() { - let _m = crate::FORK_MTX.lock(); - - // Safe: The child only calls `pause` and/or `_exit`, which are async-signal-safe. - match unsafe { fork() }.expect("Error: Fork Failed") { - Child => { - pause(); - unsafe { _exit(123) } - } - Parent { child } => { - kill(child, Some(SIGKILL)).expect("Error: Kill Failed"); - assert_eq!( - waitpid(child, None), - Ok(WaitStatus::Signaled(child, SIGKILL, false)) - ); - } - } -} - -#[test] -#[cfg(any( - target_os = "android", - target_os = "freebsd", - //target_os = "haiku", - all(target_os = "linux", not(target_env = "uclibc")), -))] -#[cfg(not(any(target_arch = "mips", target_arch = "mips64")))] -fn test_waitid_signal() { - let _m = crate::FORK_MTX.lock(); - - // Safe: The child only calls `pause` and/or `_exit`, which are async-signal-safe. - match unsafe { fork() }.expect("Error: Fork Failed") { - Child => { - pause(); - unsafe { _exit(123) } - } - Parent { child } => { - kill(child, Some(SIGKILL)).expect("Error: Kill Failed"); - assert_eq!( - waitid(Id::Pid(child), WaitPidFlag::WEXITED), - Ok(WaitStatus::Signaled(child, SIGKILL, false)), - ); - } - } -} - -#[test] -fn test_wait_exit() { - let _m = crate::FORK_MTX.lock(); - - // Safe: Child only calls `_exit`, which is async-signal-safe. - match unsafe { fork() }.expect("Error: Fork Failed") { - Child => unsafe { - _exit(12); - }, - Parent { child } => { - assert_eq!(waitpid(child, None), Ok(WaitStatus::Exited(child, 12))); - } - } -} - -#[cfg(not(target_os = "haiku"))] -#[test] -#[cfg(any( - target_os = "android", - target_os = "freebsd", - target_os = "haiku", - all(target_os = "linux", not(target_env = "uclibc")), -))] -#[cfg(not(any(target_arch = "mips", target_arch = "mips64")))] -fn test_waitid_exit() { - let _m = crate::FORK_MTX.lock(); - - // Safe: Child only calls `_exit`, which is async-signal-safe. - match unsafe { fork() }.expect("Error: Fork Failed") { - Child => unsafe { - _exit(12); - }, - Parent { child } => { - assert_eq!( - waitid(Id::Pid(child), WaitPidFlag::WEXITED), - Ok(WaitStatus::Exited(child, 12)), - ); - } - } -} - -#[test] -fn test_waitstatus_from_raw() { - let pid = Pid::from_raw(1); - assert_eq!( - WaitStatus::from_raw(pid, 0x0002), - Ok(WaitStatus::Signaled(pid, Signal::SIGINT, false)) - ); - assert_eq!( - WaitStatus::from_raw(pid, 0x0200), - Ok(WaitStatus::Exited(pid, 2)) - ); - assert_eq!(WaitStatus::from_raw(pid, 0x7f7f), Err(Errno::EINVAL)); -} - -#[test] -fn test_waitstatus_pid() { - let _m = crate::FORK_MTX.lock(); - - match unsafe { fork() }.unwrap() { - Child => unsafe { _exit(0) }, - Parent { child } => { - let status = waitpid(child, None).unwrap(); - assert_eq!(status.pid(), Some(child)); - } - } -} - -#[test] -#[cfg(any( - target_os = "android", - target_os = "freebsd", - target_os = "haiku", - all(target_os = "linux", not(target_env = "uclibc")), -))] -fn test_waitid_pid() { - let _m = crate::FORK_MTX.lock(); - - match unsafe { fork() }.unwrap() { - Child => unsafe { _exit(0) }, - Parent { child } => { - let status = waitid(Id::Pid(child), WaitPidFlag::WEXITED).unwrap(); - assert_eq!(status.pid(), Some(child)); - } - } -} - -#[cfg(any(target_os = "linux", target_os = "android"))] -// FIXME: qemu-user doesn't implement ptrace on most arches -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -mod ptrace { - use crate::*; - use libc::_exit; - use nix::sys::ptrace::{self, Event, Options}; - use nix::sys::signal::*; - use nix::sys::wait::*; - use nix::unistd::ForkResult::*; - use nix::unistd::*; - - fn ptrace_child() -> ! { - ptrace::traceme().unwrap(); - // As recommended by ptrace(2), raise SIGTRAP to pause the child - // until the parent is ready to continue - raise(SIGTRAP).unwrap(); - unsafe { _exit(0) } - } - - fn ptrace_wait_parent(child: Pid) { - // Wait for the raised SIGTRAP - assert_eq!( - waitpid(child, None), - Ok(WaitStatus::Stopped(child, SIGTRAP)) - ); - // We want to test a syscall stop and a PTRACE_EVENT stop - ptrace::setoptions( - child, - Options::PTRACE_O_TRACESYSGOOD | Options::PTRACE_O_TRACEEXIT, - ) - .expect("setoptions failed"); - - // First, stop on the next system call, which will be exit() - ptrace::syscall(child, None).expect("syscall failed"); - assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child))); - // Then get the ptrace event for the process exiting - ptrace::cont(child, None).expect("cont failed"); - assert_eq!( - waitpid(child, None), - Ok(WaitStatus::PtraceEvent( - child, - SIGTRAP, - Event::PTRACE_EVENT_EXIT as i32 - )) - ); - // Finally get the normal wait() result, now that the process has exited - ptrace::cont(child, None).expect("cont failed"); - assert_eq!(waitpid(child, None), Ok(WaitStatus::Exited(child, 0))); - } - - #[cfg(not(target_env = "uclibc"))] - fn ptrace_waitid_parent(child: Pid) { - // Wait for the raised SIGTRAP - // - // Unlike waitpid(), waitid() can distinguish trap events from regular - // stop events, so unlike ptrace_wait_parent(), we get a PtraceEvent here - assert_eq!( - waitid(Id::Pid(child), WaitPidFlag::WEXITED), - Ok(WaitStatus::PtraceEvent(child, SIGTRAP, 0)), - ); - // We want to test a syscall stop and a PTRACE_EVENT stop - ptrace::setoptions( - child, - Options::PTRACE_O_TRACESYSGOOD | Options::PTRACE_O_TRACEEXIT, - ) - .expect("setopts failed"); - - // First, stop on the next system call, which will be exit() - ptrace::syscall(child, None).expect("syscall failed"); - assert_eq!( - waitid(Id::Pid(child), WaitPidFlag::WEXITED), - Ok(WaitStatus::PtraceSyscall(child)), - ); - // Then get the ptrace event for the process exiting - ptrace::cont(child, None).expect("cont failed"); - assert_eq!( - waitid(Id::Pid(child), WaitPidFlag::WEXITED), - Ok(WaitStatus::PtraceEvent( - child, - SIGTRAP, - Event::PTRACE_EVENT_EXIT as i32 - )), - ); - // Finally get the normal wait() result, now that the process has exited - ptrace::cont(child, None).expect("cont failed"); - assert_eq!( - waitid(Id::Pid(child), WaitPidFlag::WEXITED), - Ok(WaitStatus::Exited(child, 0)), - ); - } - - #[test] - fn test_wait_ptrace() { - require_capability!("test_wait_ptrace", CAP_SYS_PTRACE); - let _m = crate::FORK_MTX.lock(); - - match unsafe { fork() }.expect("Error: Fork Failed") { - Child => ptrace_child(), - Parent { child } => ptrace_wait_parent(child), - } - } - - #[test] - #[cfg(not(target_env = "uclibc"))] - fn test_waitid_ptrace() { - require_capability!("test_waitid_ptrace", CAP_SYS_PTRACE); - let _m = crate::FORK_MTX.lock(); - - match unsafe { fork() }.expect("Error: Fork Failed") { - Child => ptrace_child(), - Parent { child } => ptrace_waitid_parent(child), - } - } -} diff --git a/vendor/nix/test/test.rs b/vendor/nix/test/test.rs deleted file mode 100644 index 6b42aad95..000000000 --- a/vendor/nix/test/test.rs +++ /dev/null @@ -1,124 +0,0 @@ -#[macro_use] -extern crate cfg_if; -#[cfg_attr(not(any(target_os = "redox", target_os = "haiku")), macro_use)] -extern crate nix; -#[macro_use] -extern crate lazy_static; - -mod common; -mod sys; -#[cfg(not(target_os = "redox"))] -mod test_dir; -mod test_fcntl; -#[cfg(any(target_os = "android", target_os = "linux"))] -mod test_kmod; -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "fushsia", - target_os = "linux", - target_os = "netbsd" -))] -mod test_mq; -#[cfg(not(target_os = "redox"))] -mod test_net; -mod test_nix_path; -#[cfg(target_os = "freebsd")] -mod test_nmount; -mod test_poll; -#[cfg(not(any( - target_os = "redox", - target_os = "fuchsia", - target_os = "haiku" -)))] -mod test_pty; -mod test_resource; -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - all(target_os = "freebsd", fbsd14), - target_os = "linux" -))] -mod test_sched; -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos" -))] -mod test_sendfile; -mod test_stat; -mod test_time; -#[cfg(all( - any( - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd" - ), - feature = "time", - feature = "signal" -))] -mod test_timer; -mod test_unistd; - -use nix::unistd::{chdir, getcwd, read}; -use parking_lot::{Mutex, RwLock, RwLockWriteGuard}; -use std::os::unix::io::RawFd; -use std::path::PathBuf; - -/// Helper function analogous to `std::io::Read::read_exact`, but for `RawFD`s -fn read_exact(f: RawFd, buf: &mut [u8]) { - let mut len = 0; - while len < buf.len() { - // get_mut would be better than split_at_mut, but it requires nightly - let (_, remaining) = buf.split_at_mut(len); - len += read(f, remaining).unwrap(); - } -} - -lazy_static! { - /// Any test that changes the process's current working directory must grab - /// the RwLock exclusively. Any process that cares about the current - /// working directory must grab it shared. - pub static ref CWD_LOCK: RwLock<()> = RwLock::new(()); - /// Any test that creates child processes must grab this mutex, regardless - /// of what it does with those children. - pub static ref FORK_MTX: Mutex<()> = Mutex::new(()); - /// Any test that changes the process's supplementary groups must grab this - /// mutex - pub static ref GROUPS_MTX: Mutex<()> = Mutex::new(()); - /// Any tests that loads or unloads kernel modules must grab this mutex - pub static ref KMOD_MTX: Mutex<()> = Mutex::new(()); - /// Any test that calls ptsname(3) must grab this mutex. - pub static ref PTSNAME_MTX: Mutex<()> = Mutex::new(()); - /// Any test that alters signal handling must grab this mutex. - pub static ref SIGNAL_MTX: Mutex<()> = Mutex::new(()); -} - -/// RAII object that restores a test's original directory on drop -struct DirRestore<'a> { - d: PathBuf, - _g: RwLockWriteGuard<'a, ()>, -} - -impl<'a> DirRestore<'a> { - fn new() -> Self { - let guard = crate::CWD_LOCK.write(); - DirRestore { - _g: guard, - d: getcwd().unwrap(), - } - } -} - -impl<'a> Drop for DirRestore<'a> { - fn drop(&mut self) { - let r = chdir(&self.d); - if std::thread::panicking() { - r.unwrap(); - } - } -} diff --git a/vendor/nix/test/test_clearenv.rs b/vendor/nix/test/test_clearenv.rs deleted file mode 100644 index 28a776804..000000000 --- a/vendor/nix/test/test_clearenv.rs +++ /dev/null @@ -1,9 +0,0 @@ -use std::env; - -#[test] -fn clearenv() { - env::set_var("FOO", "BAR"); - unsafe { nix::env::clearenv() }.unwrap(); - assert_eq!(env::var("FOO").unwrap_err(), env::VarError::NotPresent); - assert_eq!(env::vars().count(), 0); -} diff --git a/vendor/nix/test/test_dir.rs b/vendor/nix/test/test_dir.rs deleted file mode 100644 index 2af4aa5c0..000000000 --- a/vendor/nix/test/test_dir.rs +++ /dev/null @@ -1,65 +0,0 @@ -use nix::dir::{Dir, Type}; -use nix::fcntl::OFlag; -use nix::sys::stat::Mode; -use std::fs::File; -use tempfile::tempdir; - -#[cfg(test)] -fn flags() -> OFlag { - #[cfg(target_os = "illumos")] - let f = OFlag::O_RDONLY | OFlag::O_CLOEXEC; - - #[cfg(not(target_os = "illumos"))] - let f = OFlag::O_RDONLY | OFlag::O_CLOEXEC | OFlag::O_DIRECTORY; - - f -} - -#[test] -#[allow(clippy::unnecessary_sort_by)] // False positive -fn read() { - let tmp = tempdir().unwrap(); - File::create(tmp.path().join("foo")).unwrap(); - std::os::unix::fs::symlink("foo", tmp.path().join("bar")).unwrap(); - let mut dir = Dir::open(tmp.path(), flags(), Mode::empty()).unwrap(); - let mut entries: Vec<_> = dir.iter().map(|e| e.unwrap()).collect(); - entries.sort_by(|a, b| a.file_name().cmp(b.file_name())); - let entry_names: Vec<_> = entries - .iter() - .map(|e| e.file_name().to_str().unwrap().to_owned()) - .collect(); - assert_eq!(&entry_names[..], &[".", "..", "bar", "foo"]); - - // Check file types. The system is allowed to return DT_UNKNOWN (aka None here) but if it does - // return a type, ensure it's correct. - assert!(&[Some(Type::Directory), None].contains(&entries[0].file_type())); // .: dir - assert!(&[Some(Type::Directory), None].contains(&entries[1].file_type())); // ..: dir - assert!(&[Some(Type::Symlink), None].contains(&entries[2].file_type())); // bar: symlink - assert!(&[Some(Type::File), None].contains(&entries[3].file_type())); // foo: regular file -} - -#[test] -fn rewind() { - let tmp = tempdir().unwrap(); - let mut dir = Dir::open(tmp.path(), flags(), Mode::empty()).unwrap(); - let entries1: Vec<_> = dir - .iter() - .map(|e| e.unwrap().file_name().to_owned()) - .collect(); - let entries2: Vec<_> = dir - .iter() - .map(|e| e.unwrap().file_name().to_owned()) - .collect(); - let entries3: Vec<_> = dir - .into_iter() - .map(|e| e.unwrap().file_name().to_owned()) - .collect(); - assert_eq!(entries1, entries2); - assert_eq!(entries2, entries3); -} - -#[cfg(not(target_os = "haiku"))] -#[test] -fn ebadf() { - assert_eq!(Dir::from_fd(-1).unwrap_err(), nix::Error::EBADF); -} diff --git a/vendor/nix/test/test_fcntl.rs b/vendor/nix/test/test_fcntl.rs deleted file mode 100644 index e51044a06..000000000 --- a/vendor/nix/test/test_fcntl.rs +++ /dev/null @@ -1,565 +0,0 @@ -#[cfg(not(target_os = "redox"))] -use nix::errno::*; -#[cfg(not(target_os = "redox"))] -use nix::fcntl::{open, readlink, OFlag}; -#[cfg(not(target_os = "redox"))] -use nix::fcntl::{openat, readlinkat, renameat}; -#[cfg(all( - target_os = "linux", - target_env = "gnu", - any( - target_arch = "x86_64", - target_arch = "x32", - target_arch = "powerpc", - target_arch = "s390x" - ) -))] -use nix::fcntl::{renameat2, RenameFlags}; -#[cfg(not(target_os = "redox"))] -use nix::sys::stat::Mode; -#[cfg(not(target_os = "redox"))] -use nix::unistd::{close, read}; -#[cfg(not(target_os = "redox"))] -use std::fs::File; -#[cfg(not(target_os = "redox"))] -use std::io::prelude::*; -#[cfg(not(target_os = "redox"))] -use std::os::unix::fs; -#[cfg(not(target_os = "redox"))] -use tempfile::{self, NamedTempFile}; - -#[test] -#[cfg(not(target_os = "redox"))] -// QEMU does not handle openat well enough to satisfy this test -// https://gitlab.com/qemu-project/qemu/-/issues/829 -#[cfg_attr(qemu, ignore)] -fn test_openat() { - const CONTENTS: &[u8] = b"abcd"; - let mut tmp = NamedTempFile::new().unwrap(); - tmp.write_all(CONTENTS).unwrap(); - - let dirfd = - open(tmp.path().parent().unwrap(), OFlag::empty(), Mode::empty()) - .unwrap(); - let fd = openat( - dirfd, - tmp.path().file_name().unwrap(), - OFlag::O_RDONLY, - Mode::empty(), - ) - .unwrap(); - - let mut buf = [0u8; 1024]; - assert_eq!(4, read(fd, &mut buf).unwrap()); - assert_eq!(CONTENTS, &buf[0..4]); - - close(fd).unwrap(); - close(dirfd).unwrap(); -} - -#[test] -#[cfg(not(target_os = "redox"))] -fn test_renameat() { - let old_dir = tempfile::tempdir().unwrap(); - let old_dirfd = - open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); - let old_path = old_dir.path().join("old"); - File::create(old_path).unwrap(); - let new_dir = tempfile::tempdir().unwrap(); - let new_dirfd = - open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); - renameat(Some(old_dirfd), "old", Some(new_dirfd), "new").unwrap(); - assert_eq!( - renameat(Some(old_dirfd), "old", Some(new_dirfd), "new").unwrap_err(), - Errno::ENOENT - ); - close(old_dirfd).unwrap(); - close(new_dirfd).unwrap(); - assert!(new_dir.path().join("new").exists()); -} - -#[test] -#[cfg(all( - target_os = "linux", - target_env = "gnu", - any( - target_arch = "x86_64", - target_arch = "x32", - target_arch = "powerpc", - target_arch = "s390x" - ) -))] -fn test_renameat2_behaves_like_renameat_with_no_flags() { - let old_dir = tempfile::tempdir().unwrap(); - let old_dirfd = - open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); - let old_path = old_dir.path().join("old"); - File::create(old_path).unwrap(); - let new_dir = tempfile::tempdir().unwrap(); - let new_dirfd = - open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); - renameat2( - Some(old_dirfd), - "old", - Some(new_dirfd), - "new", - RenameFlags::empty(), - ) - .unwrap(); - assert_eq!( - renameat2( - Some(old_dirfd), - "old", - Some(new_dirfd), - "new", - RenameFlags::empty() - ) - .unwrap_err(), - Errno::ENOENT - ); - close(old_dirfd).unwrap(); - close(new_dirfd).unwrap(); - assert!(new_dir.path().join("new").exists()); -} - -#[test] -#[cfg(all( - target_os = "linux", - target_env = "gnu", - any( - target_arch = "x86_64", - target_arch = "x32", - target_arch = "powerpc", - target_arch = "s390x" - ) -))] -fn test_renameat2_exchange() { - let old_dir = tempfile::tempdir().unwrap(); - let old_dirfd = - open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); - let old_path = old_dir.path().join("old"); - { - let mut old_f = File::create(&old_path).unwrap(); - old_f.write_all(b"old").unwrap(); - } - let new_dir = tempfile::tempdir().unwrap(); - let new_dirfd = - open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); - let new_path = new_dir.path().join("new"); - { - let mut new_f = File::create(&new_path).unwrap(); - new_f.write_all(b"new").unwrap(); - } - renameat2( - Some(old_dirfd), - "old", - Some(new_dirfd), - "new", - RenameFlags::RENAME_EXCHANGE, - ) - .unwrap(); - let mut buf = String::new(); - let mut new_f = File::open(&new_path).unwrap(); - new_f.read_to_string(&mut buf).unwrap(); - assert_eq!(buf, "old"); - buf = "".to_string(); - let mut old_f = File::open(&old_path).unwrap(); - old_f.read_to_string(&mut buf).unwrap(); - assert_eq!(buf, "new"); - close(old_dirfd).unwrap(); - close(new_dirfd).unwrap(); -} - -#[test] -#[cfg(all( - target_os = "linux", - target_env = "gnu", - any( - target_arch = "x86_64", - target_arch = "x32", - target_arch = "powerpc", - target_arch = "s390x" - ) -))] -fn test_renameat2_noreplace() { - let old_dir = tempfile::tempdir().unwrap(); - let old_dirfd = - open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); - let old_path = old_dir.path().join("old"); - File::create(old_path).unwrap(); - let new_dir = tempfile::tempdir().unwrap(); - let new_dirfd = - open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); - let new_path = new_dir.path().join("new"); - File::create(new_path).unwrap(); - assert_eq!( - renameat2( - Some(old_dirfd), - "old", - Some(new_dirfd), - "new", - RenameFlags::RENAME_NOREPLACE - ) - .unwrap_err(), - Errno::EEXIST - ); - close(old_dirfd).unwrap(); - close(new_dirfd).unwrap(); - assert!(new_dir.path().join("new").exists()); - assert!(old_dir.path().join("old").exists()); -} - -#[test] -#[cfg(not(target_os = "redox"))] -fn test_readlink() { - let tempdir = tempfile::tempdir().unwrap(); - let src = tempdir.path().join("a"); - let dst = tempdir.path().join("b"); - println!("a: {:?}, b: {:?}", &src, &dst); - fs::symlink(src.as_path(), dst.as_path()).unwrap(); - let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); - let expected_dir = src.to_str().unwrap(); - - assert_eq!(readlink(&dst).unwrap().to_str().unwrap(), expected_dir); - assert_eq!( - readlinkat(dirfd, "b").unwrap().to_str().unwrap(), - expected_dir - ); -} - -#[cfg(any(target_os = "linux", target_os = "android"))] -mod linux_android { - use libc::loff_t; - use std::io::prelude::*; - use std::io::IoSlice; - use std::os::unix::prelude::*; - - use nix::fcntl::*; - use nix::unistd::{close, pipe, read, write}; - - use tempfile::tempfile; - #[cfg(any(target_os = "linux"))] - use tempfile::NamedTempFile; - - use crate::*; - - /// This test creates a temporary file containing the contents - /// 'foobarbaz' and uses the `copy_file_range` call to transfer - /// 3 bytes at offset 3 (`bar`) to another empty file at offset 0. The - /// resulting file is read and should contain the contents `bar`. - /// The from_offset should be updated by the call to reflect - /// the 3 bytes read (6). - #[test] - // QEMU does not support copy_file_range. Skip under qemu - #[cfg_attr(qemu, ignore)] - fn test_copy_file_range() { - const CONTENTS: &[u8] = b"foobarbaz"; - - let mut tmp1 = tempfile().unwrap(); - let mut tmp2 = tempfile().unwrap(); - - tmp1.write_all(CONTENTS).unwrap(); - tmp1.flush().unwrap(); - - let mut from_offset: i64 = 3; - copy_file_range( - tmp1.as_raw_fd(), - Some(&mut from_offset), - tmp2.as_raw_fd(), - None, - 3, - ) - .unwrap(); - - let mut res: String = String::new(); - tmp2.rewind().unwrap(); - tmp2.read_to_string(&mut res).unwrap(); - - assert_eq!(res, String::from("bar")); - assert_eq!(from_offset, 6); - } - - #[test] - fn test_splice() { - const CONTENTS: &[u8] = b"abcdef123456"; - let mut tmp = tempfile().unwrap(); - tmp.write_all(CONTENTS).unwrap(); - - let (rd, wr) = pipe().unwrap(); - let mut offset: loff_t = 5; - let res = splice( - tmp.as_raw_fd(), - Some(&mut offset), - wr, - None, - 2, - SpliceFFlags::empty(), - ) - .unwrap(); - - assert_eq!(2, res); - - let mut buf = [0u8; 1024]; - assert_eq!(2, read(rd, &mut buf).unwrap()); - assert_eq!(b"f1", &buf[0..2]); - assert_eq!(7, offset); - - close(rd).unwrap(); - close(wr).unwrap(); - } - - #[test] - fn test_tee() { - let (rd1, wr1) = pipe().unwrap(); - let (rd2, wr2) = pipe().unwrap(); - - write(wr1, b"abc").unwrap(); - let res = tee(rd1, wr2, 2, SpliceFFlags::empty()).unwrap(); - - assert_eq!(2, res); - - let mut buf = [0u8; 1024]; - - // Check the tee'd bytes are at rd2. - assert_eq!(2, read(rd2, &mut buf).unwrap()); - assert_eq!(b"ab", &buf[0..2]); - - // Check all the bytes are still at rd1. - assert_eq!(3, read(rd1, &mut buf).unwrap()); - assert_eq!(b"abc", &buf[0..3]); - - close(rd1).unwrap(); - close(wr1).unwrap(); - close(rd2).unwrap(); - close(wr2).unwrap(); - } - - #[test] - fn test_vmsplice() { - let (rd, wr) = pipe().unwrap(); - - let buf1 = b"abcdef"; - let buf2 = b"defghi"; - let iovecs = vec![IoSlice::new(&buf1[0..3]), IoSlice::new(&buf2[0..3])]; - - let res = vmsplice(wr, &iovecs[..], SpliceFFlags::empty()).unwrap(); - - assert_eq!(6, res); - - // Check the bytes can be read at rd. - let mut buf = [0u8; 32]; - assert_eq!(6, read(rd, &mut buf).unwrap()); - assert_eq!(b"abcdef", &buf[0..6]); - - close(rd).unwrap(); - close(wr).unwrap(); - } - - #[cfg(any(target_os = "linux"))] - #[test] - fn test_fallocate() { - let tmp = NamedTempFile::new().unwrap(); - - let fd = tmp.as_raw_fd(); - fallocate(fd, FallocateFlags::empty(), 0, 100).unwrap(); - - // Check if we read exactly 100 bytes - let mut buf = [0u8; 200]; - assert_eq!(100, read(fd, &mut buf).unwrap()); - } - - // The tests below are disabled for the listed targets - // due to OFD locks not being available in the kernel/libc - // versions used in the CI environment, probably because - // they run under QEMU. - - #[test] - #[cfg(all(target_os = "linux", not(target_env = "musl")))] - #[cfg_attr(target_env = "uclibc", ignore)] // uclibc doesn't support OFD locks, but the test should still compile - fn test_ofd_write_lock() { - use nix::sys::stat::fstat; - use std::mem; - - let tmp = NamedTempFile::new().unwrap(); - - let fd = tmp.as_raw_fd(); - let statfs = nix::sys::statfs::fstatfs(&tmp).unwrap(); - if statfs.filesystem_type() == nix::sys::statfs::OVERLAYFS_SUPER_MAGIC { - // OverlayFS is a union file system. It returns one inode value in - // stat(2), but a different one shows up in /proc/locks. So we must - // skip the test. - skip!("/proc/locks does not work on overlayfs"); - } - let inode = fstat(fd).expect("fstat failed").st_ino as usize; - - let mut flock: libc::flock = unsafe { - mem::zeroed() // required for Linux/mips - }; - flock.l_type = libc::F_WRLCK as libc::c_short; - flock.l_whence = libc::SEEK_SET as libc::c_short; - flock.l_start = 0; - flock.l_len = 0; - flock.l_pid = 0; - fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("write lock failed"); - assert_eq!( - Some(("OFDLCK".to_string(), "WRITE".to_string())), - lock_info(inode) - ); - - flock.l_type = libc::F_UNLCK as libc::c_short; - fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("write unlock failed"); - assert_eq!(None, lock_info(inode)); - } - - #[test] - #[cfg(all(target_os = "linux", not(target_env = "musl")))] - #[cfg_attr(target_env = "uclibc", ignore)] // uclibc doesn't support OFD locks, but the test should still compile - fn test_ofd_read_lock() { - use nix::sys::stat::fstat; - use std::mem; - - let tmp = NamedTempFile::new().unwrap(); - - let fd = tmp.as_raw_fd(); - let statfs = nix::sys::statfs::fstatfs(&tmp).unwrap(); - if statfs.filesystem_type() == nix::sys::statfs::OVERLAYFS_SUPER_MAGIC { - // OverlayFS is a union file system. It returns one inode value in - // stat(2), but a different one shows up in /proc/locks. So we must - // skip the test. - skip!("/proc/locks does not work on overlayfs"); - } - let inode = fstat(fd).expect("fstat failed").st_ino as usize; - - let mut flock: libc::flock = unsafe { - mem::zeroed() // required for Linux/mips - }; - flock.l_type = libc::F_RDLCK as libc::c_short; - flock.l_whence = libc::SEEK_SET as libc::c_short; - flock.l_start = 0; - flock.l_len = 0; - flock.l_pid = 0; - fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("read lock failed"); - assert_eq!( - Some(("OFDLCK".to_string(), "READ".to_string())), - lock_info(inode) - ); - - flock.l_type = libc::F_UNLCK as libc::c_short; - fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("read unlock failed"); - assert_eq!(None, lock_info(inode)); - } - - #[cfg(all(target_os = "linux", not(target_env = "musl")))] - fn lock_info(inode: usize) -> Option<(String, String)> { - use std::{fs::File, io::BufReader}; - - let file = File::open("/proc/locks").expect("open /proc/locks failed"); - let buf = BufReader::new(file); - - for line in buf.lines() { - let line = line.unwrap(); - let parts: Vec<_> = line.split_whitespace().collect(); - let lock_type = parts[1]; - let lock_access = parts[3]; - let ino_parts: Vec<_> = parts[5].split(':').collect(); - let ino: usize = ino_parts[2].parse().unwrap(); - if ino == inode { - return Some((lock_type.to_string(), lock_access.to_string())); - } - } - None - } -} - -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "wasi", - target_env = "uclibc", - target_os = "freebsd" -))] -mod test_posix_fadvise { - - use nix::errno::Errno; - use nix::fcntl::*; - use nix::unistd::pipe; - use std::os::unix::io::{AsRawFd, RawFd}; - use tempfile::NamedTempFile; - - #[test] - fn test_success() { - let tmp = NamedTempFile::new().unwrap(); - let fd = tmp.as_raw_fd(); - posix_fadvise(fd, 0, 100, PosixFadviseAdvice::POSIX_FADV_WILLNEED) - .expect("posix_fadvise failed"); - } - - #[test] - fn test_errno() { - let (rd, _wr) = pipe().unwrap(); - let res = posix_fadvise( - rd as RawFd, - 0, - 100, - PosixFadviseAdvice::POSIX_FADV_WILLNEED, - ); - assert_eq!(res, Err(Errno::ESPIPE)); - } -} - -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "wasi", - target_os = "freebsd" -))] -mod test_posix_fallocate { - - use nix::errno::Errno; - use nix::fcntl::*; - use nix::unistd::pipe; - use std::{ - io::Read, - os::unix::io::{AsRawFd, RawFd}, - }; - use tempfile::NamedTempFile; - - #[test] - fn success() { - const LEN: usize = 100; - let mut tmp = NamedTempFile::new().unwrap(); - let fd = tmp.as_raw_fd(); - let res = posix_fallocate(fd, 0, LEN as libc::off_t); - match res { - Ok(_) => { - let mut data = [1u8; LEN]; - assert_eq!(tmp.read(&mut data).expect("read failure"), LEN); - assert_eq!(&data[..], &[0u8; LEN][..]); - } - Err(Errno::EINVAL) => { - // POSIX requires posix_fallocate to return EINVAL both for - // invalid arguments (i.e. len < 0) and if the operation is not - // supported by the file system. - // There's no way to tell for sure whether the file system - // supports posix_fallocate, so we must pass the test if it - // returns EINVAL. - } - _ => res.unwrap(), - } - } - - #[test] - fn errno() { - let (rd, _wr) = pipe().unwrap(); - let err = posix_fallocate(rd as RawFd, 0, 100).unwrap_err(); - match err { - Errno::EINVAL | Errno::ENODEV | Errno::ESPIPE | Errno::EBADF => (), - errno => panic!("unexpected errno {}", errno,), - } - } -} diff --git a/vendor/nix/test/test_kmod/hello_mod/Makefile b/vendor/nix/test/test_kmod/hello_mod/Makefile deleted file mode 100644 index 74c99b77e..000000000 --- a/vendor/nix/test/test_kmod/hello_mod/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -obj-m += hello.o - -all: - make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules - -clean: - make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean diff --git a/vendor/nix/test/test_kmod/mod.rs b/vendor/nix/test/test_kmod/mod.rs deleted file mode 100644 index 6f9aaa897..000000000 --- a/vendor/nix/test/test_kmod/mod.rs +++ /dev/null @@ -1,188 +0,0 @@ -use crate::*; -use std::fs::copy; -use std::path::PathBuf; -use std::process::Command; -use tempfile::{tempdir, TempDir}; - -fn compile_kernel_module() -> (PathBuf, String, TempDir) { - let _m = crate::FORK_MTX.lock(); - - let tmp_dir = - tempdir().expect("unable to create temporary build directory"); - - copy( - "test/test_kmod/hello_mod/hello.c", - tmp_dir.path().join("hello.c"), - ) - .expect("unable to copy hello.c to temporary build directory"); - copy( - "test/test_kmod/hello_mod/Makefile", - tmp_dir.path().join("Makefile"), - ) - .expect("unable to copy Makefile to temporary build directory"); - - let status = Command::new("make") - .current_dir(tmp_dir.path()) - .status() - .expect("failed to run make"); - - assert!(status.success()); - - // Return the relative path of the build kernel module - (tmp_dir.path().join("hello.ko"), "hello".to_owned(), tmp_dir) -} - -use nix::errno::Errno; -use nix::kmod::{delete_module, DeleteModuleFlags}; -use nix::kmod::{finit_module, init_module, ModuleInitFlags}; -use std::ffi::CString; -use std::fs::File; -use std::io::Read; - -#[test] -fn test_finit_and_delete_module() { - require_capability!("test_finit_and_delete_module", CAP_SYS_MODULE); - let _m0 = crate::KMOD_MTX.lock(); - let _m1 = crate::CWD_LOCK.read(); - - let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module(); - - let f = File::open(kmod_path).expect("unable to open kernel module"); - finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty()) - .expect("unable to load kernel module"); - - delete_module( - &CString::new(kmod_name).unwrap(), - DeleteModuleFlags::empty(), - ) - .expect("unable to unload kernel module"); -} - -#[test] -fn test_finit_and_delete_module_with_params() { - require_capability!( - "test_finit_and_delete_module_with_params", - CAP_SYS_MODULE - ); - let _m0 = crate::KMOD_MTX.lock(); - let _m1 = crate::CWD_LOCK.read(); - - let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module(); - - let f = File::open(kmod_path).expect("unable to open kernel module"); - finit_module( - &f, - &CString::new("who=Rust number=2018").unwrap(), - ModuleInitFlags::empty(), - ) - .expect("unable to load kernel module"); - - delete_module( - &CString::new(kmod_name).unwrap(), - DeleteModuleFlags::empty(), - ) - .expect("unable to unload kernel module"); -} - -#[test] -fn test_init_and_delete_module() { - require_capability!("test_init_and_delete_module", CAP_SYS_MODULE); - let _m0 = crate::KMOD_MTX.lock(); - let _m1 = crate::CWD_LOCK.read(); - - let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module(); - - let mut f = File::open(kmod_path).expect("unable to open kernel module"); - let mut contents: Vec<u8> = Vec::new(); - f.read_to_end(&mut contents) - .expect("unable to read kernel module content to buffer"); - init_module(&contents, &CString::new("").unwrap()) - .expect("unable to load kernel module"); - - delete_module( - &CString::new(kmod_name).unwrap(), - DeleteModuleFlags::empty(), - ) - .expect("unable to unload kernel module"); -} - -#[test] -fn test_init_and_delete_module_with_params() { - require_capability!( - "test_init_and_delete_module_with_params", - CAP_SYS_MODULE - ); - let _m0 = crate::KMOD_MTX.lock(); - let _m1 = crate::CWD_LOCK.read(); - - let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module(); - - let mut f = File::open(kmod_path).expect("unable to open kernel module"); - let mut contents: Vec<u8> = Vec::new(); - f.read_to_end(&mut contents) - .expect("unable to read kernel module content to buffer"); - init_module(&contents, &CString::new("who=Nix number=2015").unwrap()) - .expect("unable to load kernel module"); - - delete_module( - &CString::new(kmod_name).unwrap(), - DeleteModuleFlags::empty(), - ) - .expect("unable to unload kernel module"); -} - -#[test] -fn test_finit_module_invalid() { - require_capability!("test_finit_module_invalid", CAP_SYS_MODULE); - let _m0 = crate::KMOD_MTX.lock(); - let _m1 = crate::CWD_LOCK.read(); - - let kmod_path = "/dev/zero"; - - let f = File::open(kmod_path).expect("unable to open kernel module"); - let result = - finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty()); - - assert_eq!(result.unwrap_err(), Errno::EINVAL); -} - -#[test] -fn test_finit_module_twice_and_delete_module() { - require_capability!( - "test_finit_module_twice_and_delete_module", - CAP_SYS_MODULE - ); - let _m0 = crate::KMOD_MTX.lock(); - let _m1 = crate::CWD_LOCK.read(); - - let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module(); - - let f = File::open(kmod_path).expect("unable to open kernel module"); - finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty()) - .expect("unable to load kernel module"); - - let result = - finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty()); - - assert_eq!(result.unwrap_err(), Errno::EEXIST); - - delete_module( - &CString::new(kmod_name).unwrap(), - DeleteModuleFlags::empty(), - ) - .expect("unable to unload kernel module"); -} - -#[test] -fn test_delete_module_not_loaded() { - require_capability!("test_delete_module_not_loaded", CAP_SYS_MODULE); - let _m0 = crate::KMOD_MTX.lock(); - let _m1 = crate::CWD_LOCK.read(); - - let result = delete_module( - &CString::new("hello").unwrap(), - DeleteModuleFlags::empty(), - ); - - assert_eq!(result.unwrap_err(), Errno::ENOENT); -} diff --git a/vendor/nix/test/test_mount.rs b/vendor/nix/test/test_mount.rs deleted file mode 100644 index 2fd612e35..000000000 --- a/vendor/nix/test/test_mount.rs +++ /dev/null @@ -1,271 +0,0 @@ -mod common; - -// Implementation note: to allow unprivileged users to run it, this test makes -// use of user and mount namespaces. On systems that allow unprivileged user -// namespaces (Linux >= 3.8 compiled with CONFIG_USER_NS), the test should run -// without root. - -#[cfg(target_os = "linux")] -mod test_mount { - use std::fs::{self, File}; - use std::io::{self, Read, Write}; - use std::os::unix::fs::OpenOptionsExt; - use std::os::unix::fs::PermissionsExt; - use std::process::{self, Command}; - - use libc::{EACCES, EROFS}; - - use nix::errno::Errno; - use nix::mount::{mount, umount, MsFlags}; - use nix::sched::{unshare, CloneFlags}; - use nix::sys::stat::{self, Mode}; - use nix::unistd::getuid; - - static SCRIPT_CONTENTS: &[u8] = b"#!/bin/sh -exit 23"; - - const EXPECTED_STATUS: i32 = 23; - - const NONE: Option<&'static [u8]> = None; - #[allow(clippy::bind_instead_of_map)] // False positive - pub fn test_mount_tmpfs_without_flags_allows_rwx() { - let tempdir = tempfile::tempdir().unwrap(); - - mount( - NONE, - tempdir.path(), - Some(b"tmpfs".as_ref()), - MsFlags::empty(), - NONE, - ) - .unwrap_or_else(|e| panic!("mount failed: {}", e)); - - let test_path = tempdir.path().join("test"); - - // Verify write. - fs::OpenOptions::new() - .create(true) - .write(true) - .mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits()) - .open(&test_path) - .or_else(|e| { - if Errno::from_i32(e.raw_os_error().unwrap()) - == Errno::EOVERFLOW - { - // Skip tests on certain Linux kernels which have a bug - // regarding tmpfs in namespaces. - // Ubuntu 14.04 and 16.04 are known to be affected; 16.10 is - // not. There is no legitimate reason for open(2) to return - // EOVERFLOW here. - // https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1659087 - let stderr = io::stderr(); - let mut handle = stderr.lock(); - writeln!( - handle, - "Buggy Linux kernel detected. Skipping test." - ) - .unwrap(); - process::exit(0); - } else { - panic!("open failed: {}", e); - } - }) - .and_then(|mut f| f.write(SCRIPT_CONTENTS)) - .unwrap_or_else(|e| panic!("write failed: {}", e)); - - // Verify read. - let mut buf = Vec::new(); - File::open(&test_path) - .and_then(|mut f| f.read_to_end(&mut buf)) - .unwrap_or_else(|e| panic!("read failed: {}", e)); - assert_eq!(buf, SCRIPT_CONTENTS); - - // Verify execute. - assert_eq!( - EXPECTED_STATUS, - Command::new(&test_path) - .status() - .unwrap_or_else(|e| panic!("exec failed: {}", e)) - .code() - .unwrap_or_else(|| panic!("child killed by signal")) - ); - - umount(tempdir.path()) - .unwrap_or_else(|e| panic!("umount failed: {}", e)); - } - - pub fn test_mount_rdonly_disallows_write() { - let tempdir = tempfile::tempdir().unwrap(); - - mount( - NONE, - tempdir.path(), - Some(b"tmpfs".as_ref()), - MsFlags::MS_RDONLY, - NONE, - ) - .unwrap_or_else(|e| panic!("mount failed: {}", e)); - - // EROFS: Read-only file system - assert_eq!( - EROFS, - File::create(tempdir.path().join("test")) - .unwrap_err() - .raw_os_error() - .unwrap() - ); - - umount(tempdir.path()) - .unwrap_or_else(|e| panic!("umount failed: {}", e)); - } - - pub fn test_mount_noexec_disallows_exec() { - let tempdir = tempfile::tempdir().unwrap(); - - mount( - NONE, - tempdir.path(), - Some(b"tmpfs".as_ref()), - MsFlags::MS_NOEXEC, - NONE, - ) - .unwrap_or_else(|e| panic!("mount failed: {}", e)); - - let test_path = tempdir.path().join("test"); - - fs::OpenOptions::new() - .create(true) - .write(true) - .mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits()) - .open(&test_path) - .and_then(|mut f| f.write(SCRIPT_CONTENTS)) - .unwrap_or_else(|e| panic!("write failed: {}", e)); - - // Verify that we cannot execute despite a+x permissions being set. - let mode = stat::Mode::from_bits_truncate( - fs::metadata(&test_path) - .map(|md| md.permissions().mode()) - .unwrap_or_else(|e| panic!("metadata failed: {}", e)), - ); - - assert!( - mode.contains(Mode::S_IXUSR | Mode::S_IXGRP | Mode::S_IXOTH), - "{:?} did not have execute permissions", - &test_path - ); - - // EACCES: Permission denied - assert_eq!( - EACCES, - Command::new(&test_path) - .status() - .unwrap_err() - .raw_os_error() - .unwrap() - ); - - umount(tempdir.path()) - .unwrap_or_else(|e| panic!("umount failed: {}", e)); - } - - pub fn test_mount_bind() { - let tempdir = tempfile::tempdir().unwrap(); - let file_name = "test"; - - { - let mount_point = tempfile::tempdir().unwrap(); - - mount( - Some(tempdir.path()), - mount_point.path(), - NONE, - MsFlags::MS_BIND, - NONE, - ) - .unwrap_or_else(|e| panic!("mount failed: {}", e)); - - fs::OpenOptions::new() - .create(true) - .write(true) - .mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits()) - .open(mount_point.path().join(file_name)) - .and_then(|mut f| f.write(SCRIPT_CONTENTS)) - .unwrap_or_else(|e| panic!("write failed: {}", e)); - - umount(mount_point.path()) - .unwrap_or_else(|e| panic!("umount failed: {}", e)); - } - - // Verify the file written in the mount shows up in source directory, even - // after unmounting. - - let mut buf = Vec::new(); - File::open(tempdir.path().join(file_name)) - .and_then(|mut f| f.read_to_end(&mut buf)) - .unwrap_or_else(|e| panic!("read failed: {}", e)); - assert_eq!(buf, SCRIPT_CONTENTS); - } - - pub fn setup_namespaces() { - // Hold on to the uid in the parent namespace. - let uid = getuid(); - - unshare(CloneFlags::CLONE_NEWNS | CloneFlags::CLONE_NEWUSER).unwrap_or_else(|e| { - let stderr = io::stderr(); - let mut handle = stderr.lock(); - writeln!(handle, - "unshare failed: {}. Are unprivileged user namespaces available?", - e).unwrap(); - writeln!(handle, "mount is not being tested").unwrap(); - // Exit with success because not all systems support unprivileged user namespaces, and - // that's not what we're testing for. - process::exit(0); - }); - - // Map user as uid 1000. - fs::OpenOptions::new() - .write(true) - .open("/proc/self/uid_map") - .and_then(|mut f| f.write(format!("1000 {} 1\n", uid).as_bytes())) - .unwrap_or_else(|e| panic!("could not write uid map: {}", e)); - } -} - -// Test runner - -/// Mimic normal test output (hackishly). -#[cfg(target_os = "linux")] -macro_rules! run_tests { - ( $($test_fn:ident),* ) => {{ - println!(); - - $( - print!("test test_mount::{} ... ", stringify!($test_fn)); - $test_fn(); - println!("ok"); - )* - - println!(); - }} -} - -#[cfg(target_os = "linux")] -fn main() { - use test_mount::{ - setup_namespaces, test_mount_bind, test_mount_noexec_disallows_exec, - test_mount_rdonly_disallows_write, - test_mount_tmpfs_without_flags_allows_rwx, - }; - skip_if_cirrus!("Fails for an unknown reason Cirrus CI. Bug #1351"); - setup_namespaces(); - - run_tests!( - test_mount_tmpfs_without_flags_allows_rwx, - test_mount_rdonly_disallows_write, - test_mount_noexec_disallows_exec, - test_mount_bind - ); -} - -#[cfg(not(target_os = "linux"))] -fn main() {} diff --git a/vendor/nix/test/test_mq.rs b/vendor/nix/test/test_mq.rs deleted file mode 100644 index 7b48e7ac7..000000000 --- a/vendor/nix/test/test_mq.rs +++ /dev/null @@ -1,190 +0,0 @@ -use cfg_if::cfg_if; -use std::ffi::CString; -use std::str; - -use nix::errno::Errno; -use nix::mqueue::{mq_attr_member_t, mq_close, mq_open, mq_receive, mq_send}; -use nix::mqueue::{MQ_OFlag, MqAttr}; -use nix::sys::stat::Mode; - -// Defined as a macro such that the error source is reported as the caller's location. -macro_rules! assert_attr_eq { - ($read_attr:ident, $initial_attr:ident) => { - cfg_if! { - if #[cfg(any(target_os = "dragonfly", target_os = "netbsd"))] { - // NetBSD (and others which inherit its implementation) include other flags - // in read_attr, such as those specified by oflag. Just make sure at least - // the correct bits are set. - assert_eq!($read_attr.flags() & $initial_attr.flags(), $initial_attr.flags()); - assert_eq!($read_attr.maxmsg(), $initial_attr.maxmsg()); - assert_eq!($read_attr.msgsize(), $initial_attr.msgsize()); - assert_eq!($read_attr.curmsgs(), $initial_attr.curmsgs()); - } else { - assert_eq!($read_attr, $initial_attr); - } - } - } -} - -#[test] -fn test_mq_send_and_receive() { - const MSG_SIZE: mq_attr_member_t = 32; - let attr = MqAttr::new(0, 10, MSG_SIZE, 0); - let mq_name = &CString::new(b"/a_nix_test_queue".as_ref()).unwrap(); - - let oflag0 = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; - let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; - let r0 = mq_open(mq_name, oflag0, mode, Some(&attr)); - if let Err(Errno::ENOSYS) = r0 { - println!("message queues not supported or module not loaded?"); - return; - }; - let mqd0 = r0.unwrap(); - let msg_to_send = "msg_1"; - mq_send(&mqd0, msg_to_send.as_bytes(), 1).unwrap(); - - let oflag1 = MQ_OFlag::O_CREAT | MQ_OFlag::O_RDONLY; - let mqd1 = mq_open(mq_name, oflag1, mode, Some(&attr)).unwrap(); - let mut buf = [0u8; 32]; - let mut prio = 0u32; - let len = mq_receive(&mqd1, &mut buf, &mut prio).unwrap(); - assert_eq!(prio, 1); - - mq_close(mqd1).unwrap(); - mq_close(mqd0).unwrap(); - assert_eq!(msg_to_send, str::from_utf8(&buf[0..len]).unwrap()); -} - -#[test] -fn test_mq_getattr() { - use nix::mqueue::mq_getattr; - const MSG_SIZE: mq_attr_member_t = 32; - let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0); - let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap(); - let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; - let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; - let r = mq_open(mq_name, oflag, mode, Some(&initial_attr)); - if let Err(Errno::ENOSYS) = r { - println!("message queues not supported or module not loaded?"); - return; - }; - let mqd = r.unwrap(); - - let read_attr = mq_getattr(&mqd).unwrap(); - assert_attr_eq!(read_attr, initial_attr); - mq_close(mqd).unwrap(); -} - -// FIXME: Fix failures for mips in QEMU -#[test] -#[cfg_attr( - all(qemu, any(target_arch = "mips", target_arch = "mips64")), - ignore -)] -fn test_mq_setattr() { - use nix::mqueue::{mq_getattr, mq_setattr}; - const MSG_SIZE: mq_attr_member_t = 32; - let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0); - let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap(); - let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; - let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; - let r = mq_open(mq_name, oflag, mode, Some(&initial_attr)); - if let Err(Errno::ENOSYS) = r { - println!("message queues not supported or module not loaded?"); - return; - }; - let mqd = r.unwrap(); - - let new_attr = MqAttr::new(0, 20, MSG_SIZE * 2, 100); - let old_attr = mq_setattr(&mqd, &new_attr).unwrap(); - assert_attr_eq!(old_attr, initial_attr); - - // No changes here because according to the Linux man page only - // O_NONBLOCK can be set (see tests below) - #[cfg(not(any(target_os = "dragonfly", target_os = "netbsd")))] - { - let new_attr_get = mq_getattr(&mqd).unwrap(); - assert_ne!(new_attr_get, new_attr); - } - - let new_attr_non_blocking = MqAttr::new( - MQ_OFlag::O_NONBLOCK.bits() as mq_attr_member_t, - 10, - MSG_SIZE, - 0, - ); - mq_setattr(&mqd, &new_attr_non_blocking).unwrap(); - let new_attr_get = mq_getattr(&mqd).unwrap(); - - // now the O_NONBLOCK flag has been set - #[cfg(not(any(target_os = "dragonfly", target_os = "netbsd")))] - { - assert_ne!(new_attr_get, initial_attr); - } - assert_attr_eq!(new_attr_get, new_attr_non_blocking); - mq_close(mqd).unwrap(); -} - -// FIXME: Fix failures for mips in QEMU -#[test] -#[cfg_attr( - all(qemu, any(target_arch = "mips", target_arch = "mips64")), - ignore -)] -fn test_mq_set_nonblocking() { - use nix::mqueue::{mq_getattr, mq_remove_nonblock, mq_set_nonblock}; - const MSG_SIZE: mq_attr_member_t = 32; - let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0); - let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap(); - let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; - let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; - let r = mq_open(mq_name, oflag, mode, Some(&initial_attr)); - if let Err(Errno::ENOSYS) = r { - println!("message queues not supported or module not loaded?"); - return; - }; - let mqd = r.unwrap(); - mq_set_nonblock(&mqd).unwrap(); - let new_attr = mq_getattr(&mqd); - let o_nonblock_bits = MQ_OFlag::O_NONBLOCK.bits() as mq_attr_member_t; - assert_eq!(new_attr.unwrap().flags() & o_nonblock_bits, o_nonblock_bits); - mq_remove_nonblock(&mqd).unwrap(); - let new_attr = mq_getattr(&mqd); - assert_eq!(new_attr.unwrap().flags() & o_nonblock_bits, 0); - mq_close(mqd).unwrap(); -} - -#[test] -fn test_mq_unlink() { - use nix::mqueue::mq_unlink; - const MSG_SIZE: mq_attr_member_t = 32; - let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0); - let mq_name_opened = &CString::new(b"/mq_unlink_test".as_ref()).unwrap(); - #[cfg(not(any(target_os = "dragonfly", target_os = "netbsd")))] - let mq_name_not_opened = - &CString::new(b"/mq_unlink_test".as_ref()).unwrap(); - let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; - let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; - let r = mq_open(mq_name_opened, oflag, mode, Some(&initial_attr)); - if let Err(Errno::ENOSYS) = r { - println!("message queues not supported or module not loaded?"); - return; - }; - let mqd = r.unwrap(); - - let res_unlink = mq_unlink(mq_name_opened); - assert_eq!(res_unlink, Ok(())); - - // NetBSD (and others which inherit its implementation) defer removing the message - // queue name until all references are closed, whereas Linux and others remove the - // message queue name immediately. - #[cfg(not(any(target_os = "dragonfly", target_os = "netbsd")))] - { - let res_unlink_not_opened = mq_unlink(mq_name_not_opened); - assert_eq!(res_unlink_not_opened, Err(Errno::ENOENT)); - } - - mq_close(mqd).unwrap(); - let res_unlink_after_close = mq_unlink(mq_name_opened); - assert_eq!(res_unlink_after_close, Err(Errno::ENOENT)); -} diff --git a/vendor/nix/test/test_net.rs b/vendor/nix/test/test_net.rs deleted file mode 100644 index c44655a4c..000000000 --- a/vendor/nix/test/test_net.rs +++ /dev/null @@ -1,19 +0,0 @@ -use nix::net::if_::*; - -#[cfg(any(target_os = "android", target_os = "linux"))] -const LOOPBACK: &[u8] = b"lo"; - -#[cfg(not(any( - target_os = "android", - target_os = "linux", - target_os = "haiku" -)))] -const LOOPBACK: &[u8] = b"lo0"; - -#[cfg(target_os = "haiku")] -const LOOPBACK: &[u8] = b"loop"; - -#[test] -fn test_if_nametoindex() { - if_nametoindex(LOOPBACK).expect("assertion failed"); -} diff --git a/vendor/nix/test/test_nix_path.rs b/vendor/nix/test/test_nix_path.rs deleted file mode 100644 index 8b1378917..000000000 --- a/vendor/nix/test/test_nix_path.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/vendor/nix/test/test_nmount.rs b/vendor/nix/test/test_nmount.rs deleted file mode 100644 index dec806a55..000000000 --- a/vendor/nix/test/test_nmount.rs +++ /dev/null @@ -1,49 +0,0 @@ -use crate::*; -use nix::{ - errno::Errno, - mount::{unmount, MntFlags, Nmount}, -}; -use std::{ffi::CString, fs::File, path::Path}; -use tempfile::tempdir; - -#[test] -fn ok() { - require_mount!("nullfs"); - - let mountpoint = tempdir().unwrap(); - let target = tempdir().unwrap(); - let _sentry = File::create(target.path().join("sentry")).unwrap(); - - let fstype = CString::new("fstype").unwrap(); - let nullfs = CString::new("nullfs").unwrap(); - Nmount::new() - .str_opt(&fstype, &nullfs) - .str_opt_owned("fspath", mountpoint.path().to_str().unwrap()) - .str_opt_owned("target", target.path().to_str().unwrap()) - .nmount(MntFlags::empty()) - .unwrap(); - - // Now check that the sentry is visible through the mountpoint - let exists = Path::exists(&mountpoint.path().join("sentry")); - - // Cleanup the mountpoint before asserting - unmount(mountpoint.path(), MntFlags::empty()).unwrap(); - - assert!(exists); -} - -#[test] -fn bad_fstype() { - let mountpoint = tempdir().unwrap(); - let target = tempdir().unwrap(); - let _sentry = File::create(target.path().join("sentry")).unwrap(); - - let e = Nmount::new() - .str_opt_owned("fspath", mountpoint.path().to_str().unwrap()) - .str_opt_owned("target", target.path().to_str().unwrap()) - .nmount(MntFlags::empty()) - .unwrap_err(); - - assert_eq!(e.error(), Errno::EINVAL); - assert_eq!(e.errmsg(), Some("Invalid fstype")); -} diff --git a/vendor/nix/test/test_poll.rs b/vendor/nix/test/test_poll.rs deleted file mode 100644 index 53964e26b..000000000 --- a/vendor/nix/test/test_poll.rs +++ /dev/null @@ -1,84 +0,0 @@ -use nix::{ - errno::Errno, - poll::{poll, PollFd, PollFlags}, - unistd::{pipe, write}, -}; - -macro_rules! loop_while_eintr { - ($poll_expr: expr) => { - loop { - match $poll_expr { - Ok(nfds) => break nfds, - Err(Errno::EINTR) => (), - Err(e) => panic!("{}", e), - } - } - }; -} - -#[test] -fn test_poll() { - let (r, w) = pipe().unwrap(); - let mut fds = [PollFd::new(r, PollFlags::POLLIN)]; - - // Poll an idle pipe. Should timeout - let nfds = loop_while_eintr!(poll(&mut fds, 100)); - assert_eq!(nfds, 0); - assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN)); - - write(w, b".").unwrap(); - - // Poll a readable pipe. Should return an event. - let nfds = poll(&mut fds, 100).unwrap(); - assert_eq!(nfds, 1); - assert!(fds[0].revents().unwrap().contains(PollFlags::POLLIN)); -} - -// ppoll(2) is the same as poll except for how it handles timeouts and signals. -// Repeating the test for poll(2) should be sufficient to check that our -// bindings are correct. -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux" -))] -#[test] -fn test_ppoll() { - use nix::poll::ppoll; - use nix::sys::signal::SigSet; - use nix::sys::time::{TimeSpec, TimeValLike}; - - let timeout = TimeSpec::milliseconds(1); - let (r, w) = pipe().unwrap(); - let mut fds = [PollFd::new(r, PollFlags::POLLIN)]; - - // Poll an idle pipe. Should timeout - let sigset = SigSet::empty(); - let nfds = loop_while_eintr!(ppoll(&mut fds, Some(timeout), Some(sigset))); - assert_eq!(nfds, 0); - assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN)); - - write(w, b".").unwrap(); - - // Poll a readable pipe. Should return an event. - let nfds = ppoll(&mut fds, Some(timeout), None).unwrap(); - assert_eq!(nfds, 1); - assert!(fds[0].revents().unwrap().contains(PollFlags::POLLIN)); -} - -#[test] -fn test_pollfd_fd() { - use std::os::unix::io::AsRawFd; - - let pfd = PollFd::new(0x1234, PollFlags::empty()); - assert_eq!(pfd.as_raw_fd(), 0x1234); -} - -#[test] -fn test_pollfd_events() { - let mut pfd = PollFd::new(-1, PollFlags::POLLIN); - assert_eq!(pfd.events(), PollFlags::POLLIN); - pfd.set_events(PollFlags::POLLOUT); - assert_eq!(pfd.events(), PollFlags::POLLOUT); -} diff --git a/vendor/nix/test/test_pty.rs b/vendor/nix/test/test_pty.rs deleted file mode 100644 index 5c27e2d63..000000000 --- a/vendor/nix/test/test_pty.rs +++ /dev/null @@ -1,313 +0,0 @@ -use std::fs::File; -use std::io::{Read, Write}; -use std::os::unix::prelude::*; -use std::path::Path; -use tempfile::tempfile; - -use libc::{_exit, STDOUT_FILENO}; -use nix::fcntl::{open, OFlag}; -use nix::pty::*; -use nix::sys::stat; -use nix::sys::termios::*; -use nix::unistd::{close, pause, write}; - -/// Regression test for Issue #659 -/// This is the correct way to explicitly close a `PtyMaster` -#[test] -fn test_explicit_close() { - let mut f = { - let m = posix_openpt(OFlag::O_RDWR).unwrap(); - close(m.into_raw_fd()).unwrap(); - tempfile().unwrap() - }; - // This should work. But if there's been a double close, then it will - // return EBADF - f.write_all(b"whatever").unwrap(); -} - -/// Test equivalence of `ptsname` and `ptsname_r` -#[test] -#[cfg(any(target_os = "android", target_os = "linux"))] -fn test_ptsname_equivalence() { - let _m = crate::PTSNAME_MTX.lock(); - - // Open a new PTTY master - let master_fd = posix_openpt(OFlag::O_RDWR).unwrap(); - assert!(master_fd.as_raw_fd() > 0); - - // Get the name of the slave - let slave_name = unsafe { ptsname(&master_fd) }.unwrap(); - let slave_name_r = ptsname_r(&master_fd).unwrap(); - assert_eq!(slave_name, slave_name_r); -} - -/// Test data copying of `ptsname` -// TODO need to run in a subprocess, since ptsname is non-reentrant -#[test] -#[cfg(any(target_os = "android", target_os = "linux"))] -fn test_ptsname_copy() { - let _m = crate::PTSNAME_MTX.lock(); - - // Open a new PTTY master - let master_fd = posix_openpt(OFlag::O_RDWR).unwrap(); - assert!(master_fd.as_raw_fd() > 0); - - // Get the name of the slave - let slave_name1 = unsafe { ptsname(&master_fd) }.unwrap(); - let slave_name2 = unsafe { ptsname(&master_fd) }.unwrap(); - assert_eq!(slave_name1, slave_name2); - // Also make sure that the string was actually copied and they point to different parts of - // memory. - assert_ne!(slave_name1.as_ptr(), slave_name2.as_ptr()); -} - -/// Test data copying of `ptsname_r` -#[test] -#[cfg(any(target_os = "android", target_os = "linux"))] -fn test_ptsname_r_copy() { - // Open a new PTTY master - let master_fd = posix_openpt(OFlag::O_RDWR).unwrap(); - assert!(master_fd.as_raw_fd() > 0); - - // Get the name of the slave - let slave_name1 = ptsname_r(&master_fd).unwrap(); - let slave_name2 = ptsname_r(&master_fd).unwrap(); - assert_eq!(slave_name1, slave_name2); - assert_ne!(slave_name1.as_ptr(), slave_name2.as_ptr()); -} - -/// Test that `ptsname` returns different names for different devices -#[test] -#[cfg(any(target_os = "android", target_os = "linux"))] -fn test_ptsname_unique() { - let _m = crate::PTSNAME_MTX.lock(); - - // Open a new PTTY master - let master1_fd = posix_openpt(OFlag::O_RDWR).unwrap(); - assert!(master1_fd.as_raw_fd() > 0); - - // Open a second PTTY master - let master2_fd = posix_openpt(OFlag::O_RDWR).unwrap(); - assert!(master2_fd.as_raw_fd() > 0); - - // Get the name of the slave - let slave_name1 = unsafe { ptsname(&master1_fd) }.unwrap(); - let slave_name2 = unsafe { ptsname(&master2_fd) }.unwrap(); - assert_ne!(slave_name1, slave_name2); -} - -/// Common setup for testing PTTY pairs -fn open_ptty_pair() -> (PtyMaster, File) { - let _m = crate::PTSNAME_MTX.lock(); - - // Open a new PTTY master - let master = posix_openpt(OFlag::O_RDWR).expect("posix_openpt failed"); - - // Allow a slave to be generated for it - grantpt(&master).expect("grantpt failed"); - unlockpt(&master).expect("unlockpt failed"); - - // Get the name of the slave - let slave_name = unsafe { ptsname(&master) }.expect("ptsname failed"); - - // Open the slave device - let slave_fd = - open(Path::new(&slave_name), OFlag::O_RDWR, stat::Mode::empty()) - .unwrap(); - - #[cfg(target_os = "illumos")] - // TODO: rewrite using ioctl! - #[allow(clippy::comparison_chain)] - { - use libc::{ioctl, I_FIND, I_PUSH}; - - // On illumos systems, as per pts(7D), one must push STREAMS modules - // after opening a device path returned from ptsname(). - let ptem = b"ptem\0"; - let ldterm = b"ldterm\0"; - let r = unsafe { ioctl(slave_fd, I_FIND, ldterm.as_ptr()) }; - if r < 0 { - panic!("I_FIND failure"); - } else if r == 0 { - if unsafe { ioctl(slave_fd, I_PUSH, ptem.as_ptr()) } < 0 { - panic!("I_PUSH ptem failure"); - } - if unsafe { ioctl(slave_fd, I_PUSH, ldterm.as_ptr()) } < 0 { - panic!("I_PUSH ldterm failure"); - } - } - } - - let slave = unsafe { File::from_raw_fd(slave_fd) }; - - (master, slave) -} - -/// Test opening a master/slave PTTY pair -/// -/// This uses a common `open_ptty_pair` because much of these functions aren't useful by -/// themselves. So for this test we perform the basic act of getting a file handle for a -/// master/slave PTTY pair, then just sanity-check the raw values. -#[test] -fn test_open_ptty_pair() { - let (master, slave) = open_ptty_pair(); - assert!(master.as_raw_fd() > 0); - assert!(slave.as_raw_fd() > 0); -} - -/// Put the terminal in raw mode. -fn make_raw(fd: RawFd) { - let mut termios = tcgetattr(fd).unwrap(); - cfmakeraw(&mut termios); - tcsetattr(fd, SetArg::TCSANOW, &termios).unwrap(); -} - -/// Test `io::Read` on the PTTY master -#[test] -fn test_read_ptty_pair() { - let (mut master, mut slave) = open_ptty_pair(); - make_raw(slave.as_raw_fd()); - - let mut buf = [0u8; 5]; - slave.write_all(b"hello").unwrap(); - master.read_exact(&mut buf).unwrap(); - assert_eq!(&buf, b"hello"); - - let mut master = &master; - slave.write_all(b"hello").unwrap(); - master.read_exact(&mut buf).unwrap(); - assert_eq!(&buf, b"hello"); -} - -/// Test `io::Write` on the PTTY master -#[test] -fn test_write_ptty_pair() { - let (mut master, mut slave) = open_ptty_pair(); - make_raw(slave.as_raw_fd()); - - let mut buf = [0u8; 5]; - master.write_all(b"adios").unwrap(); - slave.read_exact(&mut buf).unwrap(); - assert_eq!(&buf, b"adios"); - - let mut master = &master; - master.write_all(b"adios").unwrap(); - slave.read_exact(&mut buf).unwrap(); - assert_eq!(&buf, b"adios"); -} - -#[test] -fn test_openpty() { - // openpty uses ptname(3) internally - let _m = crate::PTSNAME_MTX.lock(); - - let pty = openpty(None, None).unwrap(); - assert!(pty.master > 0); - assert!(pty.slave > 0); - - // Writing to one should be readable on the other one - let string = "foofoofoo\n"; - let mut buf = [0u8; 10]; - write(pty.master, string.as_bytes()).unwrap(); - crate::read_exact(pty.slave, &mut buf); - - assert_eq!(&buf, string.as_bytes()); - - // Read the echo as well - let echoed_string = "foofoofoo\r\n"; - let mut buf = [0u8; 11]; - crate::read_exact(pty.master, &mut buf); - assert_eq!(&buf, echoed_string.as_bytes()); - - let string2 = "barbarbarbar\n"; - let echoed_string2 = "barbarbarbar\r\n"; - let mut buf = [0u8; 14]; - write(pty.slave, string2.as_bytes()).unwrap(); - crate::read_exact(pty.master, &mut buf); - - assert_eq!(&buf, echoed_string2.as_bytes()); - - close(pty.master).unwrap(); - close(pty.slave).unwrap(); -} - -#[test] -fn test_openpty_with_termios() { - // openpty uses ptname(3) internally - let _m = crate::PTSNAME_MTX.lock(); - - // Open one pty to get attributes for the second one - let mut termios = { - let pty = openpty(None, None).unwrap(); - assert!(pty.master > 0); - assert!(pty.slave > 0); - let termios = tcgetattr(pty.slave).unwrap(); - close(pty.master).unwrap(); - close(pty.slave).unwrap(); - termios - }; - // Make sure newlines are not transformed so the data is preserved when sent. - termios.output_flags.remove(OutputFlags::ONLCR); - - let pty = openpty(None, &termios).unwrap(); - // Must be valid file descriptors - assert!(pty.master > 0); - assert!(pty.slave > 0); - - // Writing to one should be readable on the other one - let string = "foofoofoo\n"; - let mut buf = [0u8; 10]; - write(pty.master, string.as_bytes()).unwrap(); - crate::read_exact(pty.slave, &mut buf); - - assert_eq!(&buf, string.as_bytes()); - - // read the echo as well - let echoed_string = "foofoofoo\n"; - crate::read_exact(pty.master, &mut buf); - assert_eq!(&buf, echoed_string.as_bytes()); - - let string2 = "barbarbarbar\n"; - let echoed_string2 = "barbarbarbar\n"; - let mut buf = [0u8; 13]; - write(pty.slave, string2.as_bytes()).unwrap(); - crate::read_exact(pty.master, &mut buf); - - assert_eq!(&buf, echoed_string2.as_bytes()); - - close(pty.master).unwrap(); - close(pty.slave).unwrap(); -} - -#[test] -fn test_forkpty() { - use nix::sys::signal::*; - use nix::sys::wait::wait; - use nix::unistd::ForkResult::*; - // forkpty calls openpty which uses ptname(3) internally. - let _m0 = crate::PTSNAME_MTX.lock(); - // forkpty spawns a child process - let _m1 = crate::FORK_MTX.lock(); - - let string = "naninani\n"; - let echoed_string = "naninani\r\n"; - let pty = unsafe { forkpty(None, None).unwrap() }; - match pty.fork_result { - Child => { - write(STDOUT_FILENO, string.as_bytes()).unwrap(); - pause(); // we need the child to stay alive until the parent calls read - unsafe { - _exit(0); - } - } - Parent { child } => { - let mut buf = [0u8; 10]; - assert!(child.as_raw() > 0); - crate::read_exact(pty.master, &mut buf); - kill(child, SIGTERM).unwrap(); - wait().unwrap(); // keep other tests using generic wait from getting our child - assert_eq!(&buf, echoed_string.as_bytes()); - close(pty.master).unwrap(); - } - } -} diff --git a/vendor/nix/test/test_ptymaster_drop.rs b/vendor/nix/test/test_ptymaster_drop.rs deleted file mode 100644 index ffbaa5697..000000000 --- a/vendor/nix/test/test_ptymaster_drop.rs +++ /dev/null @@ -1,20 +0,0 @@ -#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] -mod t { - use nix::fcntl::OFlag; - use nix::pty::*; - use nix::unistd::close; - use std::os::unix::io::AsRawFd; - - /// Regression test for Issue #659 - /// - /// `PtyMaster` should panic rather than double close the file descriptor - /// This must run in its own test process because it deliberately creates a - /// race condition. - #[test] - #[should_panic(expected = "Closing an invalid file descriptor!")] - fn test_double_close() { - let m = posix_openpt(OFlag::O_RDWR).unwrap(); - close(m.as_raw_fd()).unwrap(); - drop(m); // should panic here - } -} diff --git a/vendor/nix/test/test_resource.rs b/vendor/nix/test/test_resource.rs deleted file mode 100644 index 2ab581ba2..000000000 --- a/vendor/nix/test/test_resource.rs +++ /dev/null @@ -1,34 +0,0 @@ -#[cfg(not(any( - target_os = "redox", - target_os = "fuchsia", - target_os = "illumos", - target_os = "haiku" -)))] -use nix::sys::resource::{getrlimit, setrlimit, Resource}; - -/// Tests the RLIMIT_NOFILE functionality of getrlimit(), where the resource RLIMIT_NOFILE refers -/// to the maximum file descriptor number that can be opened by the process (aka the maximum number -/// of file descriptors that the process can open, since Linux 4.5). -/// -/// We first fetch the existing file descriptor maximum values using getrlimit(), then edit the -/// soft limit to make sure it has a new and distinct value to the hard limit. We then setrlimit() -/// to put the new soft limit in effect, and then getrlimit() once more to ensure the limits have -/// been updated. -#[test] -#[cfg(not(any( - target_os = "redox", - target_os = "fuchsia", - target_os = "illumos", - target_os = "haiku" -)))] -pub fn test_resource_limits_nofile() { - let (mut soft_limit, hard_limit) = - getrlimit(Resource::RLIMIT_NOFILE).unwrap(); - - soft_limit -= 1; - assert_ne!(soft_limit, hard_limit); - setrlimit(Resource::RLIMIT_NOFILE, soft_limit, hard_limit).unwrap(); - - let (new_soft_limit, _) = getrlimit(Resource::RLIMIT_NOFILE).unwrap(); - assert_eq!(new_soft_limit, soft_limit); -} diff --git a/vendor/nix/test/test_sched.rs b/vendor/nix/test/test_sched.rs deleted file mode 100644 index c52616b8b..000000000 --- a/vendor/nix/test/test_sched.rs +++ /dev/null @@ -1,39 +0,0 @@ -use nix::sched::{sched_getaffinity, sched_getcpu, sched_setaffinity, CpuSet}; -use nix::unistd::Pid; - -#[test] -fn test_sched_affinity() { - // If pid is zero, then the mask of the calling process is returned. - let initial_affinity = sched_getaffinity(Pid::from_raw(0)).unwrap(); - let mut at_least_one_cpu = false; - let mut last_valid_cpu = 0; - for field in 0..CpuSet::count() { - if initial_affinity.is_set(field).unwrap() { - at_least_one_cpu = true; - last_valid_cpu = field; - } - } - assert!(at_least_one_cpu); - - // Now restrict the running CPU - let mut new_affinity = CpuSet::new(); - new_affinity.set(last_valid_cpu).unwrap(); - sched_setaffinity(Pid::from_raw(0), &new_affinity).unwrap(); - - // And now re-check the affinity which should be only the one we set. - let updated_affinity = sched_getaffinity(Pid::from_raw(0)).unwrap(); - for field in 0..CpuSet::count() { - // Should be set only for the CPU we set previously - assert_eq!( - updated_affinity.is_set(field).unwrap(), - field == last_valid_cpu - ) - } - - // Now check that we're also currently running on the CPU in question. - let cur_cpu = sched_getcpu().unwrap(); - assert_eq!(cur_cpu, last_valid_cpu); - - // Finally, reset the initial CPU set - sched_setaffinity(Pid::from_raw(0), &initial_affinity).unwrap(); -} diff --git a/vendor/nix/test/test_sendfile.rs b/vendor/nix/test/test_sendfile.rs deleted file mode 100644 index f73a3b56c..000000000 --- a/vendor/nix/test/test_sendfile.rs +++ /dev/null @@ -1,208 +0,0 @@ -use std::io::prelude::*; -use std::os::unix::prelude::*; - -use libc::off_t; -use nix::sys::sendfile::*; -use tempfile::tempfile; - -cfg_if! { - if #[cfg(any(target_os = "android", target_os = "linux"))] { - use nix::unistd::{close, pipe, read}; - } else if #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "macos"))] { - use std::net::Shutdown; - use std::os::unix::net::UnixStream; - } -} - -#[cfg(any(target_os = "android", target_os = "linux"))] -#[test] -fn test_sendfile_linux() { - const CONTENTS: &[u8] = b"abcdef123456"; - let mut tmp = tempfile().unwrap(); - tmp.write_all(CONTENTS).unwrap(); - - let (rd, wr) = pipe().unwrap(); - let mut offset: off_t = 5; - let res = sendfile(wr, tmp.as_raw_fd(), Some(&mut offset), 2).unwrap(); - - assert_eq!(2, res); - - let mut buf = [0u8; 1024]; - assert_eq!(2, read(rd, &mut buf).unwrap()); - assert_eq!(b"f1", &buf[0..2]); - assert_eq!(7, offset); - - close(rd).unwrap(); - close(wr).unwrap(); -} - -#[cfg(target_os = "linux")] -#[test] -fn test_sendfile64_linux() { - const CONTENTS: &[u8] = b"abcdef123456"; - let mut tmp = tempfile().unwrap(); - tmp.write_all(CONTENTS).unwrap(); - - let (rd, wr) = pipe().unwrap(); - let mut offset: libc::off64_t = 5; - let res = sendfile64(wr, tmp.as_raw_fd(), Some(&mut offset), 2).unwrap(); - - assert_eq!(2, res); - - let mut buf = [0u8; 1024]; - assert_eq!(2, read(rd, &mut buf).unwrap()); - assert_eq!(b"f1", &buf[0..2]); - assert_eq!(7, offset); - - close(rd).unwrap(); - close(wr).unwrap(); -} - -#[cfg(target_os = "freebsd")] -#[test] -fn test_sendfile_freebsd() { - // Declare the content - let header_strings = - vec!["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"]; - let body = "Xabcdef123456"; - let body_offset = 1; - let trailer_strings = vec!["\n", "Served by Make Believe\n"]; - - // Write the body to a file - let mut tmp = tempfile().unwrap(); - tmp.write_all(body.as_bytes()).unwrap(); - - // Prepare headers and trailers for sendfile - let headers: Vec<&[u8]> = - header_strings.iter().map(|s| s.as_bytes()).collect(); - let trailers: Vec<&[u8]> = - trailer_strings.iter().map(|s| s.as_bytes()).collect(); - - // Prepare socket pair - let (mut rd, wr) = UnixStream::pair().unwrap(); - - // Call the test method - let (res, bytes_written) = sendfile( - tmp.as_raw_fd(), - wr.as_raw_fd(), - body_offset as off_t, - None, - Some(headers.as_slice()), - Some(trailers.as_slice()), - SfFlags::empty(), - 0, - ); - assert!(res.is_ok()); - wr.shutdown(Shutdown::Both).unwrap(); - - // Prepare the expected result - let expected_string = header_strings.concat() - + &body[body_offset..] - + &trailer_strings.concat(); - - // Verify the message that was sent - assert_eq!(bytes_written as usize, expected_string.as_bytes().len()); - - let mut read_string = String::new(); - let bytes_read = rd.read_to_string(&mut read_string).unwrap(); - assert_eq!(bytes_written as usize, bytes_read); - assert_eq!(expected_string, read_string); -} - -#[cfg(target_os = "dragonfly")] -#[test] -fn test_sendfile_dragonfly() { - // Declare the content - let header_strings = - vec!["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"]; - let body = "Xabcdef123456"; - let body_offset = 1; - let trailer_strings = vec!["\n", "Served by Make Believe\n"]; - - // Write the body to a file - let mut tmp = tempfile().unwrap(); - tmp.write_all(body.as_bytes()).unwrap(); - - // Prepare headers and trailers for sendfile - let headers: Vec<&[u8]> = - header_strings.iter().map(|s| s.as_bytes()).collect(); - let trailers: Vec<&[u8]> = - trailer_strings.iter().map(|s| s.as_bytes()).collect(); - - // Prepare socket pair - let (mut rd, wr) = UnixStream::pair().unwrap(); - - // Call the test method - let (res, bytes_written) = sendfile( - tmp.as_raw_fd(), - wr.as_raw_fd(), - body_offset as off_t, - None, - Some(headers.as_slice()), - Some(trailers.as_slice()), - ); - assert!(res.is_ok()); - wr.shutdown(Shutdown::Both).unwrap(); - - // Prepare the expected result - let expected_string = header_strings.concat() - + &body[body_offset..] - + &trailer_strings.concat(); - - // Verify the message that was sent - assert_eq!(bytes_written as usize, expected_string.as_bytes().len()); - - let mut read_string = String::new(); - let bytes_read = rd.read_to_string(&mut read_string).unwrap(); - assert_eq!(bytes_written as usize, bytes_read); - assert_eq!(expected_string, read_string); -} - -#[cfg(any(target_os = "ios", target_os = "macos"))] -#[test] -fn test_sendfile_darwin() { - // Declare the content - let header_strings = - vec!["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"]; - let body = "Xabcdef123456"; - let body_offset = 1; - let trailer_strings = vec!["\n", "Served by Make Believe\n"]; - - // Write the body to a file - let mut tmp = tempfile().unwrap(); - tmp.write_all(body.as_bytes()).unwrap(); - - // Prepare headers and trailers for sendfile - let headers: Vec<&[u8]> = - header_strings.iter().map(|s| s.as_bytes()).collect(); - let trailers: Vec<&[u8]> = - trailer_strings.iter().map(|s| s.as_bytes()).collect(); - - // Prepare socket pair - let (mut rd, wr) = UnixStream::pair().unwrap(); - - // Call the test method - let (res, bytes_written) = sendfile( - tmp.as_raw_fd(), - wr.as_raw_fd(), - body_offset as off_t, - None, - Some(headers.as_slice()), - Some(trailers.as_slice()), - ); - assert!(res.is_ok()); - wr.shutdown(Shutdown::Both).unwrap(); - - // Prepare the expected result - let expected_string = header_strings.concat() - + &body[body_offset..] - + &trailer_strings.concat(); - - // Verify the message that was sent - assert_eq!(bytes_written as usize, expected_string.as_bytes().len()); - - let mut read_string = String::new(); - let bytes_read = rd.read_to_string(&mut read_string).unwrap(); - assert_eq!(bytes_written as usize, bytes_read); - assert_eq!(expected_string, read_string); -} diff --git a/vendor/nix/test/test_stat.rs b/vendor/nix/test/test_stat.rs deleted file mode 100644 index 55f15c077..000000000 --- a/vendor/nix/test/test_stat.rs +++ /dev/null @@ -1,421 +0,0 @@ -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] -use std::fs; -use std::fs::File; -#[cfg(not(target_os = "redox"))] -use std::os::unix::fs::symlink; -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] -use std::os::unix::fs::PermissionsExt; -use std::os::unix::prelude::AsRawFd; -#[cfg(not(target_os = "redox"))] -use std::path::Path; -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] -use std::time::{Duration, UNIX_EPOCH}; - -use libc::mode_t; -#[cfg(not(any(target_os = "netbsd", target_os = "redox")))] -use libc::{S_IFLNK, S_IFMT}; - -#[cfg(not(target_os = "redox"))] -use nix::errno::Errno; -#[cfg(not(target_os = "redox"))] -use nix::fcntl; -#[cfg(any( - target_os = "linux", - target_os = "ios", - target_os = "macos", - target_os = "freebsd", - target_os = "netbsd" -))] -use nix::sys::stat::lutimes; -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] -use nix::sys::stat::utimensat; -#[cfg(not(target_os = "redox"))] -use nix::sys::stat::FchmodatFlags; -use nix::sys::stat::Mode; -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] -use nix::sys::stat::UtimensatFlags; -#[cfg(not(target_os = "redox"))] -use nix::sys::stat::{self}; -use nix::sys::stat::{fchmod, stat}; -#[cfg(not(target_os = "redox"))] -use nix::sys::stat::{fchmodat, mkdirat}; -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] -use nix::sys::stat::{futimens, utimes}; - -#[cfg(not(any(target_os = "netbsd", target_os = "redox")))] -use nix::sys::stat::FileStat; - -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] -use nix::sys::time::{TimeSpec, TimeVal, TimeValLike}; -#[cfg(not(target_os = "redox"))] -use nix::unistd::chdir; - -#[cfg(not(any(target_os = "netbsd", target_os = "redox")))] -use nix::Result; - -#[cfg(not(any(target_os = "netbsd", target_os = "redox")))] -fn assert_stat_results(stat_result: Result<FileStat>) { - let stats = stat_result.expect("stat call failed"); - assert!(stats.st_dev > 0); // must be positive integer, exact number machine dependent - assert!(stats.st_ino > 0); // inode is positive integer, exact number machine dependent - assert!(stats.st_mode > 0); // must be positive integer - assert_eq!(stats.st_nlink, 1); // there links created, must be 1 - assert_eq!(stats.st_size, 0); // size is 0 because we did not write anything to the file - assert!(stats.st_blksize > 0); // must be positive integer, exact number machine dependent - assert!(stats.st_blocks <= 16); // Up to 16 blocks can be allocated for a blank file -} - -#[cfg(not(any(target_os = "netbsd", target_os = "redox")))] -// (Android's st_blocks is ulonglong which is always non-negative.) -#[cfg_attr(target_os = "android", allow(unused_comparisons))] -#[allow(clippy::absurd_extreme_comparisons)] // Not absurd on all OSes -fn assert_lstat_results(stat_result: Result<FileStat>) { - let stats = stat_result.expect("stat call failed"); - assert!(stats.st_dev > 0); // must be positive integer, exact number machine dependent - assert!(stats.st_ino > 0); // inode is positive integer, exact number machine dependent - assert!(stats.st_mode > 0); // must be positive integer - - // st_mode is c_uint (u32 on Android) while S_IFMT is mode_t - // (u16 on Android), and that will be a compile error. - // On other platforms they are the same (either both are u16 or u32). - assert_eq!( - (stats.st_mode as usize) & (S_IFMT as usize), - S_IFLNK as usize - ); // should be a link - assert_eq!(stats.st_nlink, 1); // there links created, must be 1 - assert!(stats.st_size > 0); // size is > 0 because it points to another file - assert!(stats.st_blksize > 0); // must be positive integer, exact number machine dependent - - // st_blocks depends on whether the machine's file system uses fast - // or slow symlinks, so just make sure it's not negative - assert!(stats.st_blocks >= 0); -} - -#[test] -#[cfg(not(any(target_os = "netbsd", target_os = "redox")))] -fn test_stat_and_fstat() { - use nix::sys::stat::fstat; - - let tempdir = tempfile::tempdir().unwrap(); - let filename = tempdir.path().join("foo.txt"); - let file = File::create(&filename).unwrap(); - - let stat_result = stat(&filename); - assert_stat_results(stat_result); - - let fstat_result = fstat(file.as_raw_fd()); - assert_stat_results(fstat_result); -} - -#[test] -#[cfg(not(any(target_os = "netbsd", target_os = "redox")))] -fn test_fstatat() { - let tempdir = tempfile::tempdir().unwrap(); - let filename = tempdir.path().join("foo.txt"); - File::create(&filename).unwrap(); - let dirfd = - fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()); - - let result = - stat::fstatat(dirfd.unwrap(), &filename, fcntl::AtFlags::empty()); - assert_stat_results(result); -} - -#[test] -#[cfg(not(any(target_os = "netbsd", target_os = "redox")))] -fn test_stat_fstat_lstat() { - use nix::sys::stat::{fstat, lstat}; - - let tempdir = tempfile::tempdir().unwrap(); - let filename = tempdir.path().join("bar.txt"); - let linkname = tempdir.path().join("barlink"); - - File::create(&filename).unwrap(); - symlink("bar.txt", &linkname).unwrap(); - let link = File::open(&linkname).unwrap(); - - // should be the same result as calling stat, - // since it's a regular file - let stat_result = stat(&filename); - assert_stat_results(stat_result); - - let lstat_result = lstat(&linkname); - assert_lstat_results(lstat_result); - - let fstat_result = fstat(link.as_raw_fd()); - assert_stat_results(fstat_result); -} - -#[test] -fn test_fchmod() { - let tempdir = tempfile::tempdir().unwrap(); - let filename = tempdir.path().join("foo.txt"); - let file = File::create(&filename).unwrap(); - - let mut mode1 = Mode::empty(); - mode1.insert(Mode::S_IRUSR); - mode1.insert(Mode::S_IWUSR); - fchmod(file.as_raw_fd(), mode1).unwrap(); - - let file_stat1 = stat(&filename).unwrap(); - assert_eq!(file_stat1.st_mode as mode_t & 0o7777, mode1.bits()); - - let mut mode2 = Mode::empty(); - mode2.insert(Mode::S_IROTH); - fchmod(file.as_raw_fd(), mode2).unwrap(); - - let file_stat2 = stat(&filename).unwrap(); - assert_eq!(file_stat2.st_mode as mode_t & 0o7777, mode2.bits()); -} - -#[test] -#[cfg(not(target_os = "redox"))] -fn test_fchmodat() { - let _dr = crate::DirRestore::new(); - let tempdir = tempfile::tempdir().unwrap(); - let filename = "foo.txt"; - let fullpath = tempdir.path().join(filename); - File::create(&fullpath).unwrap(); - - let dirfd = - fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) - .unwrap(); - - let mut mode1 = Mode::empty(); - mode1.insert(Mode::S_IRUSR); - mode1.insert(Mode::S_IWUSR); - fchmodat(Some(dirfd), filename, mode1, FchmodatFlags::FollowSymlink) - .unwrap(); - - let file_stat1 = stat(&fullpath).unwrap(); - assert_eq!(file_stat1.st_mode as mode_t & 0o7777, mode1.bits()); - - chdir(tempdir.path()).unwrap(); - - let mut mode2 = Mode::empty(); - mode2.insert(Mode::S_IROTH); - fchmodat(None, filename, mode2, FchmodatFlags::FollowSymlink).unwrap(); - - let file_stat2 = stat(&fullpath).unwrap(); - assert_eq!(file_stat2.st_mode as mode_t & 0o7777, mode2.bits()); -} - -/// Asserts that the atime and mtime in a file's metadata match expected values. -/// -/// The atime and mtime are expressed with a resolution of seconds because some file systems -/// (like macOS's HFS+) do not have higher granularity. -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] -fn assert_times_eq( - exp_atime_sec: u64, - exp_mtime_sec: u64, - attr: &fs::Metadata, -) { - assert_eq!( - Duration::new(exp_atime_sec, 0), - attr.accessed().unwrap().duration_since(UNIX_EPOCH).unwrap() - ); - assert_eq!( - Duration::new(exp_mtime_sec, 0), - attr.modified().unwrap().duration_since(UNIX_EPOCH).unwrap() - ); -} - -#[test] -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] -fn test_utimes() { - let tempdir = tempfile::tempdir().unwrap(); - let fullpath = tempdir.path().join("file"); - drop(File::create(&fullpath).unwrap()); - - utimes(&fullpath, &TimeVal::seconds(9990), &TimeVal::seconds(5550)) - .unwrap(); - assert_times_eq(9990, 5550, &fs::metadata(&fullpath).unwrap()); -} - -#[test] -#[cfg(any( - target_os = "linux", - target_os = "ios", - target_os = "macos", - target_os = "freebsd", - target_os = "netbsd" -))] -fn test_lutimes() { - let tempdir = tempfile::tempdir().unwrap(); - let target = tempdir.path().join("target"); - let fullpath = tempdir.path().join("symlink"); - drop(File::create(&target).unwrap()); - symlink(&target, &fullpath).unwrap(); - - let exp_target_metadata = fs::symlink_metadata(&target).unwrap(); - lutimes(&fullpath, &TimeVal::seconds(4560), &TimeVal::seconds(1230)) - .unwrap(); - assert_times_eq(4560, 1230, &fs::symlink_metadata(&fullpath).unwrap()); - - let target_metadata = fs::symlink_metadata(&target).unwrap(); - assert_eq!( - exp_target_metadata.accessed().unwrap(), - target_metadata.accessed().unwrap(), - "atime of symlink target was unexpectedly modified" - ); - assert_eq!( - exp_target_metadata.modified().unwrap(), - target_metadata.modified().unwrap(), - "mtime of symlink target was unexpectedly modified" - ); -} - -#[test] -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] -fn test_futimens() { - let tempdir = tempfile::tempdir().unwrap(); - let fullpath = tempdir.path().join("file"); - drop(File::create(&fullpath).unwrap()); - - let fd = fcntl::open(&fullpath, fcntl::OFlag::empty(), stat::Mode::empty()) - .unwrap(); - - futimens(fd, &TimeSpec::seconds(10), &TimeSpec::seconds(20)).unwrap(); - assert_times_eq(10, 20, &fs::metadata(&fullpath).unwrap()); -} - -#[test] -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] -fn test_utimensat() { - let _dr = crate::DirRestore::new(); - let tempdir = tempfile::tempdir().unwrap(); - let filename = "foo.txt"; - let fullpath = tempdir.path().join(filename); - drop(File::create(&fullpath).unwrap()); - - let dirfd = - fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) - .unwrap(); - - utimensat( - Some(dirfd), - filename, - &TimeSpec::seconds(12345), - &TimeSpec::seconds(678), - UtimensatFlags::FollowSymlink, - ) - .unwrap(); - assert_times_eq(12345, 678, &fs::metadata(&fullpath).unwrap()); - - chdir(tempdir.path()).unwrap(); - - utimensat( - None, - filename, - &TimeSpec::seconds(500), - &TimeSpec::seconds(800), - UtimensatFlags::FollowSymlink, - ) - .unwrap(); - assert_times_eq(500, 800, &fs::metadata(&fullpath).unwrap()); -} - -#[test] -#[cfg(not(target_os = "redox"))] -fn test_mkdirat_success_path() { - let tempdir = tempfile::tempdir().unwrap(); - let filename = "example_subdir"; - let dirfd = - fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) - .unwrap(); - mkdirat(dirfd, filename, Mode::S_IRWXU).expect("mkdirat failed"); - assert!(Path::exists(&tempdir.path().join(filename))); -} - -#[test] -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] -fn test_mkdirat_success_mode() { - let expected_bits = - stat::SFlag::S_IFDIR.bits() | stat::Mode::S_IRWXU.bits(); - let tempdir = tempfile::tempdir().unwrap(); - let filename = "example_subdir"; - let dirfd = - fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) - .unwrap(); - mkdirat(dirfd, filename, Mode::S_IRWXU).expect("mkdirat failed"); - let permissions = fs::metadata(tempdir.path().join(filename)) - .unwrap() - .permissions(); - let mode = permissions.mode(); - assert_eq!(mode as mode_t, expected_bits) -} - -#[test] -#[cfg(not(target_os = "redox"))] -fn test_mkdirat_fail() { - let tempdir = tempfile::tempdir().unwrap(); - let not_dir_filename = "example_not_dir"; - let filename = "example_subdir_dir"; - let dirfd = fcntl::open( - &tempdir.path().join(not_dir_filename), - fcntl::OFlag::O_CREAT, - stat::Mode::empty(), - ) - .unwrap(); - let result = mkdirat(dirfd, filename, Mode::S_IRWXU).unwrap_err(); - assert_eq!(result, Errno::ENOTDIR); -} - -#[test] -#[cfg(not(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "haiku", - target_os = "redox" -)))] -fn test_mknod() { - use stat::{lstat, mknod, SFlag}; - - let file_name = "test_file"; - let tempdir = tempfile::tempdir().unwrap(); - let target = tempdir.path().join(file_name); - mknod(&target, SFlag::S_IFREG, Mode::S_IRWXU, 0).unwrap(); - let mode = lstat(&target).unwrap().st_mode as mode_t; - assert_eq!(mode & libc::S_IFREG, libc::S_IFREG); - assert_eq!(mode & libc::S_IRWXU, libc::S_IRWXU); -} - -#[test] -#[cfg(not(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", - target_os = "macos", - target_os = "haiku", - target_os = "redox" -)))] -fn test_mknodat() { - use fcntl::{AtFlags, OFlag}; - use nix::dir::Dir; - use stat::{fstatat, mknodat, SFlag}; - - let file_name = "test_file"; - let tempdir = tempfile::tempdir().unwrap(); - let target_dir = - Dir::open(tempdir.path(), OFlag::O_DIRECTORY, Mode::S_IRWXU).unwrap(); - mknodat( - target_dir.as_raw_fd(), - file_name, - SFlag::S_IFREG, - Mode::S_IRWXU, - 0, - ) - .unwrap(); - let mode = fstatat( - target_dir.as_raw_fd(), - file_name, - AtFlags::AT_SYMLINK_NOFOLLOW, - ) - .unwrap() - .st_mode as mode_t; - assert_eq!(mode & libc::S_IFREG, libc::S_IFREG); - assert_eq!(mode & libc::S_IRWXU, libc::S_IRWXU); -} diff --git a/vendor/nix/test/test_time.rs b/vendor/nix/test/test_time.rs deleted file mode 100644 index 5f76e61a2..000000000 --- a/vendor/nix/test/test_time.rs +++ /dev/null @@ -1,59 +0,0 @@ -#[cfg(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "linux", - target_os = "android", - target_os = "emscripten", -))] -use nix::time::clock_getcpuclockid; -use nix::time::{clock_gettime, ClockId}; - -#[cfg(not(target_os = "redox"))] -#[test] -pub fn test_clock_getres() { - nix::time::clock_getres(ClockId::CLOCK_REALTIME).expect("assertion failed"); -} - -#[test] -pub fn test_clock_gettime() { - clock_gettime(ClockId::CLOCK_REALTIME).expect("assertion failed"); -} - -#[cfg(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "linux", - target_os = "android", - target_os = "emscripten", -))] -#[test] -pub fn test_clock_getcpuclockid() { - let clock_id = clock_getcpuclockid(nix::unistd::Pid::this()).unwrap(); - clock_gettime(clock_id).unwrap(); -} - -#[cfg(not(target_os = "redox"))] -#[test] -pub fn test_clock_id_res() { - ClockId::CLOCK_REALTIME.res().unwrap(); -} - -#[test] -pub fn test_clock_id_now() { - ClockId::CLOCK_REALTIME.now().unwrap(); -} - -#[cfg(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "linux", - target_os = "android", - target_os = "emscripten", -))] -#[test] -pub fn test_clock_id_pid_cpu_clock_id() { - ClockId::pid_cpu_clock_id(nix::unistd::Pid::this()) - .map(ClockId::now) - .unwrap() - .unwrap(); -} diff --git a/vendor/nix/test/test_timer.rs b/vendor/nix/test/test_timer.rs deleted file mode 100644 index ffd146867..000000000 --- a/vendor/nix/test/test_timer.rs +++ /dev/null @@ -1,102 +0,0 @@ -use nix::sys::signal::{ - sigaction, SaFlags, SigAction, SigEvent, SigHandler, SigSet, SigevNotify, - Signal, -}; -use nix::sys::timer::{Expiration, Timer, TimerSetTimeFlags}; -use nix::time::ClockId; -use std::convert::TryFrom; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::thread; -use std::time::{Duration, Instant}; - -const SIG: Signal = Signal::SIGALRM; -static ALARM_CALLED: AtomicBool = AtomicBool::new(false); - -pub extern "C" fn handle_sigalarm(raw_signal: libc::c_int) { - let signal = Signal::try_from(raw_signal).unwrap(); - if signal == SIG { - ALARM_CALLED.store(true, Ordering::Release); - } -} - -#[test] -fn alarm_fires() { - // Avoid interfering with other signal using tests by taking a mutex shared - // among other tests in this crate. - let _m = crate::SIGNAL_MTX.lock(); - const TIMER_PERIOD: Duration = Duration::from_millis(100); - - // - // Setup - // - - // Create a handler for the test signal, `SIG`. The handler is responsible - // for flipping `ALARM_CALLED`. - let handler = SigHandler::Handler(handle_sigalarm); - let signal_action = - SigAction::new(handler, SaFlags::SA_RESTART, SigSet::empty()); - let old_handler = unsafe { - sigaction(SIG, &signal_action) - .expect("unable to set signal handler for alarm") - }; - - // Create the timer. We use the monotonic clock here, though any would do - // really. The timer is set to fire every 250 milliseconds with no delay for - // the initial firing. - let clockid = ClockId::CLOCK_MONOTONIC; - let sigevent = SigEvent::new(SigevNotify::SigevSignal { - signal: SIG, - si_value: 0, - }); - let mut timer = - Timer::new(clockid, sigevent).expect("failed to create timer"); - let expiration = Expiration::Interval(TIMER_PERIOD.into()); - let flags = TimerSetTimeFlags::empty(); - timer.set(expiration, flags).expect("could not set timer"); - - // - // Test - // - - // Determine that there's still an expiration tracked by the - // timer. Depending on when this runs either an `Expiration::Interval` or - // `Expiration::IntervalDelayed` will be present. That is, if the timer has - // not fired yet we'll get our original `expiration`, else the one that - // represents a delay to the next expiration. We're only interested in the - // timer still being extant. - match timer.get() { - Ok(Some(exp)) => assert!(matches!( - exp, - Expiration::Interval(..) | Expiration::IntervalDelayed(..) - )), - _ => panic!("timer lost its expiration"), - } - - // Wait for 2 firings of the alarm before checking that it has fired and - // been handled at least the once. If we wait for 3 seconds and the handler - // is never called something has gone sideways and the test fails. - let starttime = Instant::now(); - loop { - thread::sleep(2 * TIMER_PERIOD); - if ALARM_CALLED.load(Ordering::Acquire) { - break; - } - if starttime.elapsed() > Duration::from_secs(3) { - panic!("Timeout waiting for SIGALRM"); - } - } - - // Cleanup: - // 1) deregister the OS's timer. - // 2) Wait for a full timer period, since POSIX does not require that - // disabling the timer will clear pending signals, and on NetBSD at least - // it does not. - // 2) Replace the old signal handler now that we've completed the test. If - // the test fails this process panics, so the fact we might not get here - // is okay. - drop(timer); - thread::sleep(TIMER_PERIOD); - unsafe { - sigaction(SIG, &old_handler).expect("unable to reset signal handler"); - } -} diff --git a/vendor/nix/test/test_unistd.rs b/vendor/nix/test/test_unistd.rs deleted file mode 100644 index 9e20f977e..000000000 --- a/vendor/nix/test/test_unistd.rs +++ /dev/null @@ -1,1407 +0,0 @@ -use libc::{_exit, mode_t, off_t}; -use nix::errno::Errno; -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] -use nix::fcntl::readlink; -use nix::fcntl::OFlag; -#[cfg(not(target_os = "redox"))] -use nix::fcntl::{self, open}; -#[cfg(not(any( - target_os = "redox", - target_os = "fuchsia", - target_os = "haiku" -)))] -use nix::pty::{grantpt, posix_openpt, ptsname, unlockpt}; -#[cfg(not(target_os = "redox"))] -use nix::sys::signal::{ - sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal, -}; -use nix::sys::stat::{self, Mode, SFlag}; -use nix::sys::wait::*; -use nix::unistd::ForkResult::*; -use nix::unistd::*; -use std::env; -#[cfg(not(any(target_os = "fuchsia", target_os = "redox")))] -use std::ffi::CString; -#[cfg(not(target_os = "redox"))] -use std::fs::DirBuilder; -use std::fs::{self, File}; -use std::io::Write; -use std::os::unix::prelude::*; -#[cfg(not(any( - target_os = "fuchsia", - target_os = "redox", - target_os = "haiku" -)))] -use std::path::Path; -use tempfile::{tempdir, tempfile}; - -use crate::*; - -#[test] -#[cfg(not(any(target_os = "netbsd")))] -fn test_fork_and_waitpid() { - let _m = crate::FORK_MTX.lock(); - - // Safe: Child only calls `_exit`, which is signal-safe - match unsafe { fork() }.expect("Error: Fork Failed") { - Child => unsafe { _exit(0) }, - Parent { child } => { - // assert that child was created and pid > 0 - let child_raw: ::libc::pid_t = child.into(); - assert!(child_raw > 0); - let wait_status = waitpid(child, None); - match wait_status { - // assert that waitpid returned correct status and the pid is the one of the child - Ok(WaitStatus::Exited(pid_t, _)) => assert_eq!(pid_t, child), - - // panic, must never happen - s @ Ok(_) => { - panic!("Child exited {:?}, should never happen", s) - } - - // panic, waitpid should never fail - Err(s) => panic!("Error: waitpid returned Err({:?}", s), - } - } - } -} - -#[test] -fn test_wait() { - // Grab FORK_MTX so wait doesn't reap a different test's child process - let _m = crate::FORK_MTX.lock(); - - // Safe: Child only calls `_exit`, which is signal-safe - match unsafe { fork() }.expect("Error: Fork Failed") { - Child => unsafe { _exit(0) }, - Parent { child } => { - let wait_status = wait(); - - // just assert that (any) one child returns with WaitStatus::Exited - assert_eq!(wait_status, Ok(WaitStatus::Exited(child, 0))); - } - } -} - -#[test] -fn test_mkstemp() { - let mut path = env::temp_dir(); - path.push("nix_tempfile.XXXXXX"); - - let result = mkstemp(&path); - match result { - Ok((fd, path)) => { - close(fd).unwrap(); - unlink(path.as_path()).unwrap(); - } - Err(e) => panic!("mkstemp failed: {}", e), - } -} - -#[test] -fn test_mkstemp_directory() { - // mkstemp should fail if a directory is given - mkstemp(&env::temp_dir()).expect_err("assertion failed"); -} - -#[test] -#[cfg(not(target_os = "redox"))] -fn test_mkfifo() { - let tempdir = tempdir().unwrap(); - let mkfifo_fifo = tempdir.path().join("mkfifo_fifo"); - - mkfifo(&mkfifo_fifo, Mode::S_IRUSR).unwrap(); - - let stats = stat::stat(&mkfifo_fifo).unwrap(); - let typ = stat::SFlag::from_bits_truncate(stats.st_mode as mode_t); - assert_eq!(typ, SFlag::S_IFIFO); -} - -#[test] -#[cfg(not(target_os = "redox"))] -fn test_mkfifo_directory() { - // mkfifo should fail if a directory is given - mkfifo(&env::temp_dir(), Mode::S_IRUSR).expect_err("assertion failed"); -} - -#[test] -#[cfg(not(any( - target_os = "macos", - target_os = "ios", - target_os = "android", - target_os = "redox", - target_os = "haiku" -)))] -fn test_mkfifoat_none() { - let _m = crate::CWD_LOCK.read(); - - let tempdir = tempdir().unwrap(); - let mkfifoat_fifo = tempdir.path().join("mkfifoat_fifo"); - - mkfifoat(None, &mkfifoat_fifo, Mode::S_IRUSR).unwrap(); - - let stats = stat::stat(&mkfifoat_fifo).unwrap(); - let typ = stat::SFlag::from_bits_truncate(stats.st_mode); - assert_eq!(typ, SFlag::S_IFIFO); -} - -#[test] -#[cfg(not(any( - target_os = "macos", - target_os = "ios", - target_os = "android", - target_os = "redox", - target_os = "haiku" -)))] -fn test_mkfifoat() { - use nix::fcntl; - - let tempdir = tempdir().unwrap(); - let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); - let mkfifoat_name = "mkfifoat_name"; - - mkfifoat(Some(dirfd), mkfifoat_name, Mode::S_IRUSR).unwrap(); - - let stats = - stat::fstatat(dirfd, mkfifoat_name, fcntl::AtFlags::empty()).unwrap(); - let typ = stat::SFlag::from_bits_truncate(stats.st_mode); - assert_eq!(typ, SFlag::S_IFIFO); -} - -#[test] -#[cfg(not(any( - target_os = "macos", - target_os = "ios", - target_os = "android", - target_os = "redox", - target_os = "haiku" -)))] -fn test_mkfifoat_directory_none() { - let _m = crate::CWD_LOCK.read(); - - // mkfifoat should fail if a directory is given - mkfifoat(None, &env::temp_dir(), Mode::S_IRUSR) - .expect_err("assertion failed"); -} - -#[test] -#[cfg(not(any( - target_os = "macos", - target_os = "ios", - target_os = "android", - target_os = "redox", - target_os = "haiku" -)))] -fn test_mkfifoat_directory() { - // mkfifoat should fail if a directory is given - let tempdir = tempdir().unwrap(); - let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); - let mkfifoat_dir = "mkfifoat_dir"; - stat::mkdirat(dirfd, mkfifoat_dir, Mode::S_IRUSR).unwrap(); - - mkfifoat(Some(dirfd), mkfifoat_dir, Mode::S_IRUSR) - .expect_err("assertion failed"); -} - -#[test] -fn test_getpid() { - let pid: ::libc::pid_t = getpid().into(); - let ppid: ::libc::pid_t = getppid().into(); - assert!(pid > 0); - assert!(ppid > 0); -} - -#[test] -#[cfg(not(target_os = "redox"))] -fn test_getsid() { - let none_sid: ::libc::pid_t = getsid(None).unwrap().into(); - let pid_sid: ::libc::pid_t = getsid(Some(getpid())).unwrap().into(); - assert!(none_sid > 0); - assert_eq!(none_sid, pid_sid); -} - -#[cfg(any(target_os = "linux", target_os = "android"))] -mod linux_android { - use nix::unistd::gettid; - - #[test] - fn test_gettid() { - let tid: ::libc::pid_t = gettid().into(); - assert!(tid > 0); - } -} - -#[test] -// `getgroups()` and `setgroups()` do not behave as expected on Apple platforms -#[cfg(not(any( - target_os = "ios", - target_os = "macos", - target_os = "redox", - target_os = "fuchsia", - target_os = "haiku" -)))] -fn test_setgroups() { - // Skip this test when not run as root as `setgroups()` requires root. - skip_if_not_root!("test_setgroups"); - - let _m = crate::GROUPS_MTX.lock(); - - // Save the existing groups - let old_groups = getgroups().unwrap(); - - // Set some new made up groups - let groups = [Gid::from_raw(123), Gid::from_raw(456)]; - setgroups(&groups).unwrap(); - - let new_groups = getgroups().unwrap(); - assert_eq!(new_groups, groups); - - // Revert back to the old groups - setgroups(&old_groups).unwrap(); -} - -#[test] -// `getgroups()` and `setgroups()` do not behave as expected on Apple platforms -#[cfg(not(any( - target_os = "ios", - target_os = "macos", - target_os = "redox", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos" -)))] -fn test_initgroups() { - // Skip this test when not run as root as `initgroups()` and `setgroups()` - // require root. - skip_if_not_root!("test_initgroups"); - - let _m = crate::GROUPS_MTX.lock(); - - // Save the existing groups - let old_groups = getgroups().unwrap(); - - // It doesn't matter if the root user is not called "root" or if a user - // called "root" doesn't exist. We are just checking that the extra, - // made-up group, `123`, is set. - // FIXME: Test the other half of initgroups' functionality: whether the - // groups that the user belongs to are also set. - let user = CString::new("root").unwrap(); - let group = Gid::from_raw(123); - let group_list = getgrouplist(&user, group).unwrap(); - assert!(group_list.contains(&group)); - - initgroups(&user, group).unwrap(); - - let new_groups = getgroups().unwrap(); - assert_eq!(new_groups, group_list); - - // Revert back to the old groups - setgroups(&old_groups).unwrap(); -} - -#[cfg(not(any(target_os = "fuchsia", target_os = "redox")))] -macro_rules! execve_test_factory ( - ($test_name:ident, $syscall:ident, $exe: expr $(, $pathname:expr, $flags:expr)*) => ( - - #[cfg(test)] - mod $test_name { - use std::ffi::CStr; - use super::*; - - const EMPTY: &'static [u8] = b"\0"; - const DASH_C: &'static [u8] = b"-c\0"; - const BIGARG: &'static [u8] = b"echo nix!!! && echo foo=$foo && echo baz=$baz\0"; - const FOO: &'static [u8] = b"foo=bar\0"; - const BAZ: &'static [u8] = b"baz=quux\0"; - - fn syscall_cstr_ref() -> Result<std::convert::Infallible, nix::Error> { - $syscall( - $exe, - $(CString::new($pathname).unwrap().as_c_str(), )* - &[CStr::from_bytes_with_nul(EMPTY).unwrap(), - CStr::from_bytes_with_nul(DASH_C).unwrap(), - CStr::from_bytes_with_nul(BIGARG).unwrap()], - &[CStr::from_bytes_with_nul(FOO).unwrap(), - CStr::from_bytes_with_nul(BAZ).unwrap()] - $(, $flags)*) - } - - fn syscall_cstring() -> Result<std::convert::Infallible, nix::Error> { - $syscall( - $exe, - $(CString::new($pathname).unwrap().as_c_str(), )* - &[CString::from(CStr::from_bytes_with_nul(EMPTY).unwrap()), - CString::from(CStr::from_bytes_with_nul(DASH_C).unwrap()), - CString::from(CStr::from_bytes_with_nul(BIGARG).unwrap())], - &[CString::from(CStr::from_bytes_with_nul(FOO).unwrap()), - CString::from(CStr::from_bytes_with_nul(BAZ).unwrap())] - $(, $flags)*) - } - - fn common_test(syscall: fn() -> Result<std::convert::Infallible, nix::Error>) { - if "execveat" == stringify!($syscall) { - // Though undocumented, Docker's default seccomp profile seems to - // block this syscall. https://github.com/nix-rust/nix/issues/1122 - skip_if_seccomp!($test_name); - } - - let m = crate::FORK_MTX.lock(); - // The `exec`d process will write to `writer`, and we'll read that - // data from `reader`. - let (reader, writer) = pipe().unwrap(); - - // Safe: Child calls `exit`, `dup`, `close` and the provided `exec*` family function. - // NOTE: Technically, this makes the macro unsafe to use because you could pass anything. - // The tests make sure not to do that, though. - match unsafe{fork()}.unwrap() { - Child => { - // Make `writer` be the stdout of the new process. - dup2(writer, 1).unwrap(); - let r = syscall(); - let _ = std::io::stderr() - .write_all(format!("{:?}", r).as_bytes()); - // Should only get here in event of error - unsafe{ _exit(1) }; - }, - Parent { child } => { - // Wait for the child to exit. - let ws = waitpid(child, None); - drop(m); - assert_eq!(ws, Ok(WaitStatus::Exited(child, 0))); - // Read 1024 bytes. - let mut buf = [0u8; 1024]; - read(reader, &mut buf).unwrap(); - // It should contain the things we printed using `/bin/sh`. - let string = String::from_utf8_lossy(&buf); - assert!(string.contains("nix!!!")); - assert!(string.contains("foo=bar")); - assert!(string.contains("baz=quux")); - } - } - } - - // These tests frequently fail on musl, probably due to - // https://github.com/nix-rust/nix/issues/555 - #[cfg_attr(target_env = "musl", ignore)] - #[test] - fn test_cstr_ref() { - common_test(syscall_cstr_ref); - } - - // These tests frequently fail on musl, probably due to - // https://github.com/nix-rust/nix/issues/555 - #[cfg_attr(target_env = "musl", ignore)] - #[test] - fn test_cstring() { - common_test(syscall_cstring); - } - } - - ) -); - -cfg_if! { - if #[cfg(target_os = "android")] { - execve_test_factory!(test_execve, execve, CString::new("/system/bin/sh").unwrap().as_c_str()); - execve_test_factory!(test_fexecve, fexecve, File::open("/system/bin/sh").unwrap().into_raw_fd()); - } else if #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux"))] { - // These tests frequently fail on musl, probably due to - // https://github.com/nix-rust/nix/issues/555 - execve_test_factory!(test_execve, execve, CString::new("/bin/sh").unwrap().as_c_str()); - execve_test_factory!(test_fexecve, fexecve, File::open("/bin/sh").unwrap().into_raw_fd()); - } else if #[cfg(any(target_os = "illumos", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris"))] { - execve_test_factory!(test_execve, execve, CString::new("/bin/sh").unwrap().as_c_str()); - // No fexecve() on ios, macos, NetBSD, OpenBSD. - } -} - -#[cfg(any(target_os = "haiku", target_os = "linux", target_os = "openbsd"))] -execve_test_factory!(test_execvpe, execvpe, &CString::new("sh").unwrap()); - -cfg_if! { - if #[cfg(target_os = "android")] { - use nix::fcntl::AtFlags; - execve_test_factory!(test_execveat_empty, execveat, - File::open("/system/bin/sh").unwrap().into_raw_fd(), - "", AtFlags::AT_EMPTY_PATH); - execve_test_factory!(test_execveat_relative, execveat, - File::open("/system/bin/").unwrap().into_raw_fd(), - "./sh", AtFlags::empty()); - execve_test_factory!(test_execveat_absolute, execveat, - File::open("/").unwrap().into_raw_fd(), - "/system/bin/sh", AtFlags::empty()); - } else if #[cfg(all(target_os = "linux", any(target_arch ="x86_64", target_arch ="x86")))] { - use nix::fcntl::AtFlags; - execve_test_factory!(test_execveat_empty, execveat, File::open("/bin/sh").unwrap().into_raw_fd(), - "", AtFlags::AT_EMPTY_PATH); - execve_test_factory!(test_execveat_relative, execveat, File::open("/bin/").unwrap().into_raw_fd(), - "./sh", AtFlags::empty()); - execve_test_factory!(test_execveat_absolute, execveat, File::open("/").unwrap().into_raw_fd(), - "/bin/sh", AtFlags::empty()); - } -} - -#[test] -#[cfg(not(target_os = "fuchsia"))] -fn test_fchdir() { - // fchdir changes the process's cwd - let _dr = crate::DirRestore::new(); - - let tmpdir = tempdir().unwrap(); - let tmpdir_path = tmpdir.path().canonicalize().unwrap(); - let tmpdir_fd = File::open(&tmpdir_path).unwrap().into_raw_fd(); - - fchdir(tmpdir_fd).expect("assertion failed"); - assert_eq!(getcwd().unwrap(), tmpdir_path); - - close(tmpdir_fd).expect("assertion failed"); -} - -#[test] -fn test_getcwd() { - // chdir changes the process's cwd - let _dr = crate::DirRestore::new(); - - let tmpdir = tempdir().unwrap(); - let tmpdir_path = tmpdir.path().canonicalize().unwrap(); - chdir(&tmpdir_path).expect("assertion failed"); - assert_eq!(getcwd().unwrap(), tmpdir_path); - - // make path 500 chars longer so that buffer doubling in getcwd - // kicks in. Note: One path cannot be longer than 255 bytes - // (NAME_MAX) whole path cannot be longer than PATH_MAX (usually - // 4096 on linux, 1024 on macos) - let mut inner_tmp_dir = tmpdir_path; - for _ in 0..5 { - let newdir = "a".repeat(100); - inner_tmp_dir.push(newdir); - mkdir(inner_tmp_dir.as_path(), Mode::S_IRWXU) - .expect("assertion failed"); - } - chdir(inner_tmp_dir.as_path()).expect("assertion failed"); - assert_eq!(getcwd().unwrap(), inner_tmp_dir.as_path()); -} - -#[test] -fn test_chown() { - // Testing for anything other than our own UID/GID is hard. - let uid = Some(getuid()); - let gid = Some(getgid()); - - let tempdir = tempdir().unwrap(); - let path = tempdir.path().join("file"); - { - File::create(&path).unwrap(); - } - - chown(&path, uid, gid).unwrap(); - chown(&path, uid, None).unwrap(); - chown(&path, None, gid).unwrap(); - - fs::remove_file(&path).unwrap(); - chown(&path, uid, gid).unwrap_err(); -} - -#[test] -fn test_fchown() { - // Testing for anything other than our own UID/GID is hard. - let uid = Some(getuid()); - let gid = Some(getgid()); - - let path = tempfile().unwrap(); - let fd = path.as_raw_fd(); - - fchown(fd, uid, gid).unwrap(); - fchown(fd, uid, None).unwrap(); - fchown(fd, None, gid).unwrap(); - fchown(999999999, uid, gid).unwrap_err(); -} - -#[test] -#[cfg(not(target_os = "redox"))] -fn test_fchownat() { - let _dr = crate::DirRestore::new(); - // Testing for anything other than our own UID/GID is hard. - let uid = Some(getuid()); - let gid = Some(getgid()); - - let tempdir = tempdir().unwrap(); - let path = tempdir.path().join("file"); - { - File::create(&path).unwrap(); - } - - let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); - - fchownat(Some(dirfd), "file", uid, gid, FchownatFlags::FollowSymlink) - .unwrap(); - - chdir(tempdir.path()).unwrap(); - fchownat(None, "file", uid, gid, FchownatFlags::FollowSymlink).unwrap(); - - fs::remove_file(&path).unwrap(); - fchownat(None, "file", uid, gid, FchownatFlags::FollowSymlink).unwrap_err(); -} - -#[test] -fn test_lseek() { - const CONTENTS: &[u8] = b"abcdef123456"; - let mut tmp = tempfile().unwrap(); - tmp.write_all(CONTENTS).unwrap(); - let tmpfd = tmp.into_raw_fd(); - - let offset: off_t = 5; - lseek(tmpfd, offset, Whence::SeekSet).unwrap(); - - let mut buf = [0u8; 7]; - crate::read_exact(tmpfd, &mut buf); - assert_eq!(b"f123456", &buf); - - close(tmpfd).unwrap(); -} - -#[cfg(any(target_os = "linux", target_os = "android"))] -#[test] -fn test_lseek64() { - const CONTENTS: &[u8] = b"abcdef123456"; - let mut tmp = tempfile().unwrap(); - tmp.write_all(CONTENTS).unwrap(); - let tmpfd = tmp.into_raw_fd(); - - lseek64(tmpfd, 5, Whence::SeekSet).unwrap(); - - let mut buf = [0u8; 7]; - crate::read_exact(tmpfd, &mut buf); - assert_eq!(b"f123456", &buf); - - close(tmpfd).unwrap(); -} - -cfg_if! { - if #[cfg(any(target_os = "android", target_os = "linux"))] { - macro_rules! require_acct{ - () => { - require_capability!("test_acct", CAP_SYS_PACCT); - } - } - } else if #[cfg(target_os = "freebsd")] { - macro_rules! require_acct{ - () => { - skip_if_not_root!("test_acct"); - skip_if_jailed!("test_acct"); - } - } - } else if #[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "haiku")))] { - macro_rules! require_acct{ - () => { - skip_if_not_root!("test_acct"); - } - } - } -} - -#[test] -#[cfg(not(any( - target_os = "redox", - target_os = "fuchsia", - target_os = "haiku" -)))] -fn test_acct() { - use std::process::Command; - use std::{thread, time}; - use tempfile::NamedTempFile; - - let _m = crate::FORK_MTX.lock(); - require_acct!(); - - let file = NamedTempFile::new().unwrap(); - let path = file.path().to_str().unwrap(); - - acct::enable(path).unwrap(); - - loop { - Command::new("echo").arg("Hello world").output().unwrap(); - let len = fs::metadata(path).unwrap().len(); - if len > 0 { - break; - } - thread::sleep(time::Duration::from_millis(10)); - } - acct::disable().unwrap(); -} - -#[test] -fn test_fpathconf_limited() { - let f = tempfile().unwrap(); - // AFAIK, PATH_MAX is limited on all platforms, so it makes a good test - let path_max = fpathconf(f.as_raw_fd(), PathconfVar::PATH_MAX); - assert!( - path_max - .expect("fpathconf failed") - .expect("PATH_MAX is unlimited") - > 0 - ); -} - -#[test] -fn test_pathconf_limited() { - // AFAIK, PATH_MAX is limited on all platforms, so it makes a good test - let path_max = pathconf("/", PathconfVar::PATH_MAX); - assert!( - path_max - .expect("pathconf failed") - .expect("PATH_MAX is unlimited") - > 0 - ); -} - -#[test] -fn test_sysconf_limited() { - // AFAIK, OPEN_MAX is limited on all platforms, so it makes a good test - let open_max = sysconf(SysconfVar::OPEN_MAX); - assert!( - open_max - .expect("sysconf failed") - .expect("OPEN_MAX is unlimited") - > 0 - ); -} - -#[cfg(target_os = "freebsd")] -#[test] -fn test_sysconf_unsupported() { - // I know of no sysconf variables that are unsupported everywhere, but - // _XOPEN_CRYPT is unsupported on FreeBSD 11.0, which is one of the platforms - // we test. - let open_max = sysconf(SysconfVar::_XOPEN_CRYPT); - assert!(open_max.expect("sysconf failed").is_none()) -} - -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd" -))] -#[test] -fn test_getresuid() { - let resuids = getresuid().unwrap(); - assert_ne!(resuids.real.as_raw(), libc::uid_t::MAX); - assert_ne!(resuids.effective.as_raw(), libc::uid_t::MAX); - assert_ne!(resuids.saved.as_raw(), libc::uid_t::MAX); -} - -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd" -))] -#[test] -fn test_getresgid() { - let resgids = getresgid().unwrap(); - assert_ne!(resgids.real.as_raw(), libc::gid_t::MAX); - assert_ne!(resgids.effective.as_raw(), libc::gid_t::MAX); - assert_ne!(resgids.saved.as_raw(), libc::gid_t::MAX); -} - -// Test that we can create a pair of pipes. No need to verify that they pass -// data; that's the domain of the OS, not nix. -#[test] -fn test_pipe() { - let (fd0, fd1) = pipe().unwrap(); - let m0 = stat::SFlag::from_bits_truncate( - stat::fstat(fd0).unwrap().st_mode as mode_t, - ); - // S_IFIFO means it's a pipe - assert_eq!(m0, SFlag::S_IFIFO); - let m1 = stat::SFlag::from_bits_truncate( - stat::fstat(fd1).unwrap().st_mode as mode_t, - ); - assert_eq!(m1, SFlag::S_IFIFO); -} - -// pipe2(2) is the same as pipe(2), except it allows setting some flags. Check -// that we can set a flag. -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - target_os = "redox", - target_os = "solaris" -))] -#[test] -fn test_pipe2() { - use nix::fcntl::{fcntl, FcntlArg, FdFlag}; - - let (fd0, fd1) = pipe2(OFlag::O_CLOEXEC).unwrap(); - let f0 = FdFlag::from_bits_truncate(fcntl(fd0, FcntlArg::F_GETFD).unwrap()); - assert!(f0.contains(FdFlag::FD_CLOEXEC)); - let f1 = FdFlag::from_bits_truncate(fcntl(fd1, FcntlArg::F_GETFD).unwrap()); - assert!(f1.contains(FdFlag::FD_CLOEXEC)); -} - -#[test] -#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] -fn test_truncate() { - let tempdir = tempdir().unwrap(); - let path = tempdir.path().join("file"); - - { - let mut tmp = File::create(&path).unwrap(); - const CONTENTS: &[u8] = b"12345678"; - tmp.write_all(CONTENTS).unwrap(); - } - - truncate(&path, 4).unwrap(); - - let metadata = fs::metadata(&path).unwrap(); - assert_eq!(4, metadata.len()); -} - -#[test] -fn test_ftruncate() { - let tempdir = tempdir().unwrap(); - let path = tempdir.path().join("file"); - - let tmpfd = { - let mut tmp = File::create(&path).unwrap(); - const CONTENTS: &[u8] = b"12345678"; - tmp.write_all(CONTENTS).unwrap(); - tmp.into_raw_fd() - }; - - ftruncate(tmpfd, 2).unwrap(); - close(tmpfd).unwrap(); - - let metadata = fs::metadata(&path).unwrap(); - assert_eq!(2, metadata.len()); -} - -// Used in `test_alarm`. -#[cfg(not(target_os = "redox"))] -static mut ALARM_CALLED: bool = false; - -// Used in `test_alarm`. -#[cfg(not(target_os = "redox"))] -pub extern "C" fn alarm_signal_handler(raw_signal: libc::c_int) { - assert_eq!( - raw_signal, - libc::SIGALRM, - "unexpected signal: {}", - raw_signal - ); - unsafe { ALARM_CALLED = true }; -} - -#[test] -#[cfg(not(target_os = "redox"))] -fn test_alarm() { - use std::{ - thread, - time::{Duration, Instant}, - }; - - // Maybe other tests that fork interfere with this one? - let _m = crate::SIGNAL_MTX.lock(); - - let handler = SigHandler::Handler(alarm_signal_handler); - let signal_action = - SigAction::new(handler, SaFlags::SA_RESTART, SigSet::empty()); - let old_handler = unsafe { - sigaction(Signal::SIGALRM, &signal_action) - .expect("unable to set signal handler for alarm") - }; - - // Set an alarm. - assert_eq!(alarm::set(60), None); - - // Overwriting an alarm should return the old alarm. - assert_eq!(alarm::set(1), Some(60)); - - // We should be woken up after 1 second by the alarm, so we'll sleep for 3 - // seconds to be sure. - let starttime = Instant::now(); - loop { - thread::sleep(Duration::from_millis(100)); - if unsafe { ALARM_CALLED } { - break; - } - if starttime.elapsed() > Duration::from_secs(3) { - panic!("Timeout waiting for SIGALRM"); - } - } - - // Reset the signal. - unsafe { - sigaction(Signal::SIGALRM, &old_handler) - .expect("unable to set signal handler for alarm"); - } -} - -#[test] -#[cfg(not(target_os = "redox"))] -fn test_canceling_alarm() { - let _m = crate::SIGNAL_MTX.lock(); - - assert_eq!(alarm::cancel(), None); - - assert_eq!(alarm::set(60), None); - assert_eq!(alarm::cancel(), Some(60)); -} - -#[test] -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] -fn test_symlinkat() { - let _m = crate::CWD_LOCK.read(); - - let tempdir = tempdir().unwrap(); - - let target = tempdir.path().join("a"); - let linkpath = tempdir.path().join("b"); - symlinkat(&target, None, &linkpath).unwrap(); - assert_eq!( - readlink(&linkpath).unwrap().to_str().unwrap(), - target.to_str().unwrap() - ); - - let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); - let target = "c"; - let linkpath = "d"; - symlinkat(target, Some(dirfd), linkpath).unwrap(); - assert_eq!( - readlink(&tempdir.path().join(linkpath)) - .unwrap() - .to_str() - .unwrap(), - target - ); -} - -#[test] -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] -fn test_linkat_file() { - let tempdir = tempdir().unwrap(); - let oldfilename = "foo.txt"; - let oldfilepath = tempdir.path().join(oldfilename); - - let newfilename = "bar.txt"; - let newfilepath = tempdir.path().join(newfilename); - - // Create file - File::create(oldfilepath).unwrap(); - - // Get file descriptor for base directory - let dirfd = - fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) - .unwrap(); - - // Attempt hard link file at relative path - linkat( - Some(dirfd), - oldfilename, - Some(dirfd), - newfilename, - LinkatFlags::SymlinkFollow, - ) - .unwrap(); - assert!(newfilepath.exists()); -} - -#[test] -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] -fn test_linkat_olddirfd_none() { - let _dr = crate::DirRestore::new(); - - let tempdir_oldfile = tempdir().unwrap(); - let oldfilename = "foo.txt"; - let oldfilepath = tempdir_oldfile.path().join(oldfilename); - - let tempdir_newfile = tempdir().unwrap(); - let newfilename = "bar.txt"; - let newfilepath = tempdir_newfile.path().join(newfilename); - - // Create file - File::create(oldfilepath).unwrap(); - - // Get file descriptor for base directory of new file - let dirfd = fcntl::open( - tempdir_newfile.path(), - fcntl::OFlag::empty(), - stat::Mode::empty(), - ) - .unwrap(); - - // Attempt hard link file using curent working directory as relative path for old file path - chdir(tempdir_oldfile.path()).unwrap(); - linkat( - None, - oldfilename, - Some(dirfd), - newfilename, - LinkatFlags::SymlinkFollow, - ) - .unwrap(); - assert!(newfilepath.exists()); -} - -#[test] -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] -fn test_linkat_newdirfd_none() { - let _dr = crate::DirRestore::new(); - - let tempdir_oldfile = tempdir().unwrap(); - let oldfilename = "foo.txt"; - let oldfilepath = tempdir_oldfile.path().join(oldfilename); - - let tempdir_newfile = tempdir().unwrap(); - let newfilename = "bar.txt"; - let newfilepath = tempdir_newfile.path().join(newfilename); - - // Create file - File::create(oldfilepath).unwrap(); - - // Get file descriptor for base directory of old file - let dirfd = fcntl::open( - tempdir_oldfile.path(), - fcntl::OFlag::empty(), - stat::Mode::empty(), - ) - .unwrap(); - - // Attempt hard link file using current working directory as relative path for new file path - chdir(tempdir_newfile.path()).unwrap(); - linkat( - Some(dirfd), - oldfilename, - None, - newfilename, - LinkatFlags::SymlinkFollow, - ) - .unwrap(); - assert!(newfilepath.exists()); -} - -#[test] -#[cfg(not(any( - target_os = "ios", - target_os = "macos", - target_os = "redox", - target_os = "haiku" -)))] -fn test_linkat_no_follow_symlink() { - let _m = crate::CWD_LOCK.read(); - - let tempdir = tempdir().unwrap(); - let oldfilename = "foo.txt"; - let oldfilepath = tempdir.path().join(oldfilename); - - let symoldfilename = "symfoo.txt"; - let symoldfilepath = tempdir.path().join(symoldfilename); - - let newfilename = "nofollowsymbar.txt"; - let newfilepath = tempdir.path().join(newfilename); - - // Create file - File::create(&oldfilepath).unwrap(); - - // Create symlink to file - symlinkat(&oldfilepath, None, &symoldfilepath).unwrap(); - - // Get file descriptor for base directory - let dirfd = - fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) - .unwrap(); - - // Attempt link symlink of file at relative path - linkat( - Some(dirfd), - symoldfilename, - Some(dirfd), - newfilename, - LinkatFlags::NoSymlinkFollow, - ) - .unwrap(); - - // Assert newfile is actually a symlink to oldfile. - assert_eq!( - readlink(&newfilepath).unwrap().to_str().unwrap(), - oldfilepath.to_str().unwrap() - ); -} - -#[test] -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] -fn test_linkat_follow_symlink() { - let _m = crate::CWD_LOCK.read(); - - let tempdir = tempdir().unwrap(); - let oldfilename = "foo.txt"; - let oldfilepath = tempdir.path().join(oldfilename); - - let symoldfilename = "symfoo.txt"; - let symoldfilepath = tempdir.path().join(symoldfilename); - - let newfilename = "nofollowsymbar.txt"; - let newfilepath = tempdir.path().join(newfilename); - - // Create file - File::create(&oldfilepath).unwrap(); - - // Create symlink to file - symlinkat(&oldfilepath, None, &symoldfilepath).unwrap(); - - // Get file descriptor for base directory - let dirfd = - fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) - .unwrap(); - - // Attempt link target of symlink of file at relative path - linkat( - Some(dirfd), - symoldfilename, - Some(dirfd), - newfilename, - LinkatFlags::SymlinkFollow, - ) - .unwrap(); - - let newfilestat = stat::stat(&newfilepath).unwrap(); - - // Check the file type of the new link - assert_eq!( - (stat::SFlag::from_bits_truncate(newfilestat.st_mode as mode_t) - & SFlag::S_IFMT), - SFlag::S_IFREG - ); - - // Check the number of hard links to the original file - assert_eq!(newfilestat.st_nlink, 2); -} - -#[test] -#[cfg(not(target_os = "redox"))] -fn test_unlinkat_dir_noremovedir() { - let tempdir = tempdir().unwrap(); - let dirname = "foo_dir"; - let dirpath = tempdir.path().join(dirname); - - // Create dir - DirBuilder::new().recursive(true).create(dirpath).unwrap(); - - // Get file descriptor for base directory - let dirfd = - fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) - .unwrap(); - - // Attempt unlink dir at relative path without proper flag - let err_result = - unlinkat(Some(dirfd), dirname, UnlinkatFlags::NoRemoveDir).unwrap_err(); - assert!(err_result == Errno::EISDIR || err_result == Errno::EPERM); -} - -#[test] -#[cfg(not(target_os = "redox"))] -fn test_unlinkat_dir_removedir() { - let tempdir = tempdir().unwrap(); - let dirname = "foo_dir"; - let dirpath = tempdir.path().join(dirname); - - // Create dir - DirBuilder::new().recursive(true).create(&dirpath).unwrap(); - - // Get file descriptor for base directory - let dirfd = - fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) - .unwrap(); - - // Attempt unlink dir at relative path with proper flag - unlinkat(Some(dirfd), dirname, UnlinkatFlags::RemoveDir).unwrap(); - assert!(!dirpath.exists()); -} - -#[test] -#[cfg(not(target_os = "redox"))] -fn test_unlinkat_file() { - let tempdir = tempdir().unwrap(); - let filename = "foo.txt"; - let filepath = tempdir.path().join(filename); - - // Create file - File::create(&filepath).unwrap(); - - // Get file descriptor for base directory - let dirfd = - fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) - .unwrap(); - - // Attempt unlink file at relative path - unlinkat(Some(dirfd), filename, UnlinkatFlags::NoRemoveDir).unwrap(); - assert!(!filepath.exists()); -} - -#[test] -fn test_access_not_existing() { - let tempdir = tempdir().unwrap(); - let dir = tempdir.path().join("does_not_exist.txt"); - assert_eq!( - access(&dir, AccessFlags::F_OK).err().unwrap(), - Errno::ENOENT - ); -} - -#[test] -fn test_access_file_exists() { - let tempdir = tempdir().unwrap(); - let path = tempdir.path().join("does_exist.txt"); - let _file = File::create(path.clone()).unwrap(); - access(&path, AccessFlags::R_OK | AccessFlags::W_OK) - .expect("assertion failed"); -} - -//Clippy false positive https://github.com/rust-lang/rust-clippy/issues/9111 -#[allow(clippy::needless_borrow)] -#[cfg(not(target_os = "redox"))] -#[test] -fn test_user_into_passwd() { - // get the UID of the "nobody" user - #[cfg(not(target_os = "haiku"))] - let test_username = "nobody"; - // "nobody" unavailable on haiku - #[cfg(target_os = "haiku")] - let test_username = "user"; - - let nobody = User::from_name(test_username).unwrap().unwrap(); - let pwd: libc::passwd = nobody.into(); - let _: User = (&pwd).into(); -} - -/// Tests setting the filesystem UID with `setfsuid`. -#[cfg(any(target_os = "linux", target_os = "android"))] -#[test] -fn test_setfsuid() { - use std::os::unix::fs::PermissionsExt; - use std::{fs, io, thread}; - require_capability!("test_setfsuid", CAP_SETUID); - - // get the UID of the "nobody" user - let nobody = User::from_name("nobody").unwrap().unwrap(); - - // create a temporary file with permissions '-rw-r-----' - let file = tempfile::NamedTempFile::new_in("/var/tmp").unwrap(); - let temp_path = file.into_temp_path(); - let temp_path_2 = temp_path.to_path_buf(); - let mut permissions = fs::metadata(&temp_path).unwrap().permissions(); - permissions.set_mode(0o640); - - // spawn a new thread where to test setfsuid - thread::spawn(move || { - // set filesystem UID - let fuid = setfsuid(nobody.uid); - // trying to open the temporary file should fail with EACCES - let res = fs::File::open(&temp_path); - let err = res.expect_err("assertion failed"); - assert_eq!(err.kind(), io::ErrorKind::PermissionDenied); - - // assert fuid actually changes - let prev_fuid = setfsuid(Uid::from_raw(-1i32 as u32)); - assert_ne!(prev_fuid, fuid); - }) - .join() - .unwrap(); - - // open the temporary file with the current thread filesystem UID - fs::File::open(temp_path_2).unwrap(); -} - -#[test] -#[cfg(not(any( - target_os = "redox", - target_os = "fuchsia", - target_os = "haiku" -)))] -fn test_ttyname() { - let fd = posix_openpt(OFlag::O_RDWR).expect("posix_openpt failed"); - assert!(fd.as_raw_fd() > 0); - - // on linux, we can just call ttyname on the pty master directly, but - // apparently osx requires that ttyname is called on a slave pty (can't - // find this documented anywhere, but it seems to empirically be the case) - grantpt(&fd).expect("grantpt failed"); - unlockpt(&fd).expect("unlockpt failed"); - let sname = unsafe { ptsname(&fd) }.expect("ptsname failed"); - let fds = open(Path::new(&sname), OFlag::O_RDWR, stat::Mode::empty()) - .expect("open failed"); - assert!(fds > 0); - - let name = ttyname(fds).expect("ttyname failed"); - assert!(name.starts_with("/dev")); -} - -#[test] -#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] -fn test_ttyname_not_pty() { - let fd = File::open("/dev/zero").unwrap(); - assert!(fd.as_raw_fd() > 0); - assert_eq!(ttyname(fd.as_raw_fd()), Err(Errno::ENOTTY)); -} - -#[test] -#[cfg(not(any( - target_os = "redox", - target_os = "fuchsia", - target_os = "haiku" -)))] -fn test_ttyname_invalid_fd() { - assert_eq!(ttyname(-1), Err(Errno::EBADF)); -} - -#[test] -#[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "dragonfly", -))] -fn test_getpeereid() { - use std::os::unix::net::UnixStream; - let (sock_a, sock_b) = UnixStream::pair().unwrap(); - - let (uid_a, gid_a) = getpeereid(sock_a.as_raw_fd()).unwrap(); - let (uid_b, gid_b) = getpeereid(sock_b.as_raw_fd()).unwrap(); - - let uid = geteuid(); - let gid = getegid(); - - assert_eq!(uid, uid_a); - assert_eq!(gid, gid_a); - assert_eq!(uid_a, uid_b); - assert_eq!(gid_a, gid_b); -} - -#[test] -#[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "dragonfly", -))] -fn test_getpeereid_invalid_fd() { - // getpeereid is not POSIX, so error codes are inconsistent between different Unices. - getpeereid(-1).expect_err("assertion failed"); -} - -#[test] -#[cfg(not(target_os = "redox"))] -fn test_faccessat_none_not_existing() { - use nix::fcntl::AtFlags; - let tempdir = tempfile::tempdir().unwrap(); - let dir = tempdir.path().join("does_not_exist.txt"); - assert_eq!( - faccessat(None, &dir, AccessFlags::F_OK, AtFlags::empty()) - .err() - .unwrap(), - Errno::ENOENT - ); -} - -#[test] -#[cfg(not(target_os = "redox"))] -fn test_faccessat_not_existing() { - use nix::fcntl::AtFlags; - let tempdir = tempfile::tempdir().unwrap(); - let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); - let not_exist_file = "does_not_exist.txt"; - assert_eq!( - faccessat( - Some(dirfd), - not_exist_file, - AccessFlags::F_OK, - AtFlags::empty(), - ) - .err() - .unwrap(), - Errno::ENOENT - ); -} - -#[test] -#[cfg(not(target_os = "redox"))] -fn test_faccessat_none_file_exists() { - use nix::fcntl::AtFlags; - let tempdir = tempfile::tempdir().unwrap(); - let path = tempdir.path().join("does_exist.txt"); - let _file = File::create(path.clone()).unwrap(); - assert!(faccessat( - None, - &path, - AccessFlags::R_OK | AccessFlags::W_OK, - AtFlags::empty(), - ) - .is_ok()); -} - -#[test] -#[cfg(not(target_os = "redox"))] -fn test_faccessat_file_exists() { - use nix::fcntl::AtFlags; - let tempdir = tempfile::tempdir().unwrap(); - let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); - let exist_file = "does_exist.txt"; - let path = tempdir.path().join(exist_file); - let _file = File::create(path.clone()).unwrap(); - assert!(faccessat( - Some(dirfd), - &path, - AccessFlags::R_OK | AccessFlags::W_OK, - AtFlags::empty(), - ) - .is_ok()); -} - -#[test] -#[cfg(any( - all(target_os = "linux", not(target_env = "uclibc")), - target_os = "freebsd", - target_os = "dragonfly" -))] -fn test_eaccess_not_existing() { - let tempdir = tempdir().unwrap(); - let dir = tempdir.path().join("does_not_exist.txt"); - assert_eq!( - eaccess(&dir, AccessFlags::F_OK).err().unwrap(), - Errno::ENOENT - ); -} - -#[test] -#[cfg(any( - all(target_os = "linux", not(target_env = "uclibc")), - target_os = "freebsd", - target_os = "dragonfly" -))] -fn test_eaccess_file_exists() { - let tempdir = tempdir().unwrap(); - let path = tempdir.path().join("does_exist.txt"); - let _file = File::create(path.clone()).unwrap(); - eaccess(&path, AccessFlags::R_OK | AccessFlags::W_OK) - .expect("assertion failed"); -} |