diff options
Diffstat (limited to 'third_party/rust/nix')
97 files changed, 7661 insertions, 6486 deletions
diff --git a/third_party/rust/nix/.cargo-checksum.json b/third_party/rust/nix/.cargo-checksum.json index d48e123da2..3cd04958ea 100644 --- a/third_party/rust/nix/.cargo-checksum.json +++ b/third_party/rust/nix/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"92468d08ccd20acf93bac25d983dbaedbd6dafbfdebf45d670a557e1dd993650","Cargo.toml":"8e68a73dcb2ac8fd7a01b714c3c08c0148d0cbeb1b8a2bbb30ff10cf0332b505","LICENSE":"66e3ee1fa7f909ad3c612d556f2a0cdabcd809ad6e66f3b0605015ac64841b70","README.md":"693748b472aa697105dbaf37ad95e41b9b3ed6480533e03a5a93b10ec70c987a","src/dir.rs":"d40e2bc1df553898e718de552ddb57a160b9957b7d6a0f7e27e3e7fe6af536ab","src/env.rs":"028bc5e20139ebba418a655a2978a53335dc7680bf1de43d2c8333dd72cfa5c4","src/errno.rs":"3c2935cc3238c13a545ab8ceb6a8aa9fd03a9cbf72be041e9ea032f6ee19c2f4","src/fcntl.rs":"8cda1abc82c562b2340b3d27176b674b65d0e1c4bf888e7700c6b50e63c3bf0d","src/features.rs":"5381d43a7759c0bf4a26fc25c602d507beafa85282764bdbae6eff59f98fd16d","src/ifaddrs.rs":"377865eb48040d28c392a1aec0221320108e3392ea285d23405ae2cfa5c54b20","src/kmod.rs":"d2ef26c35db790e589f6418c1631aa48b01d4ea5674e050c12d1cfa7a18681ef","src/lib.rs":"571f418caf6a9646939ae4976ec4bde5f9325e9b4320715c9586590b9d8d4963","src/macros.rs":"73ab3b56f4b7cd08d3c70f035cd74bcbdac17ff05946adc875e05fd93280eb7e","src/mount/bsd.rs":"9f12470d33d9b3d18fdba5a10952f6e76b254df3d8794f296437d266db9623c4","src/mount/linux.rs":"6b0ea0c4598f5537e2dc57bdad6d3acc86e29d258aef3a639e1a2308f38bdb0e","src/mount/mod.rs":"ba9f60eb831224ab73bdd87e00e15d13b9ce9efb70b18bf8f3fe60406d522b3e","src/mqueue.rs":"0c78ef1a52c2df05a48b390707764dfca27c056033e01d604a1aa91058c7e9b4","src/net/if_.rs":"fa7413a9676e552b3fa0576081b83ac91278bb0d7240b7cdd962ea911336bba0","src/net/mod.rs":"577f70170e53d4a6de1abb70bf8f1031ec3e65c0e63ef5fcf05c907125e7ac17","src/poll.rs":"8b26383af51ff0733e07e6a5a2e174462e8849b1118ca12bdf3540d40a298602","src/pty.rs":"6a1122c4e7ea236cc4e1e36e2eb587eddf1e323edacdbcdd3b3c1619a60eedbf","src/sched.rs":"217055e50a54398e5b75a247e1be9a81a764aadd0267bcf6367f633e9b277f84","src/sys/aio.rs":"3e2e93dff85180a98b2b09b1ea926f89ee17d235c60fd2a96adf0ff7db601e5c","src/sys/epoll.rs":"5c45733ea19802443cc3f9e21766013d4ff0125a52dbf5f5a13f10ff19914e1e","src/sys/event.rs":"9b3b02c42f471e3d9f974be1b60aab11ff4d1fc79692c3d40991f0c22ca9ea83","src/sys/eventfd.rs":"22c1205c948aeb29f7a8a0f298644eb393778585ecbd2091d40559e0ed2de06b","src/sys/inotify.rs":"68b80856937286a23917638ed8f5fc057e396fe7c4f4d1178865e720ba7dba95","src/sys/ioctl/bsd.rs":"bbd02e30b0a78c1cb22777d9b00cfcbba9c68505cffc06118ac68474cf6fea39","src/sys/ioctl/linux.rs":"2aec4b3b3beb8119b9bb0c8001b9bb66cba3f2ff778c432e62f2da4243787184","src/sys/ioctl/mod.rs":"80e683efac7d1e2bd88680f028370f7c778e6a5097cae7845566bc8f43f4ff4f","src/sys/memfd.rs":"e2653a3c476585e993d9e8551cd0f991ba141c6bb46d9ece7fa6fd5cdeb862ae","src/sys/mman.rs":"4604656656a061606f99ff2f117c8f7463cd87aedaa4b3de5de863056bec5499","src/sys/mod.rs":"f5a5f1b51bbd2c865bbda2652bf0d2fd38e0773bd1a37460869c5a7008d27f03","src/sys/personality.rs":"8fbd8b522b8be4591a4cf25cba023884d3ad39b26666708d43eb79b81bf1c203","src/sys/prctl.rs":"d5b695099d4ac1b44e552988f488d7b88d285e68968ac29b93c153da52acd2bf","src/sys/pthread.rs":"258cdf7ff0b61a4afa6d228109e4cb4fb88d859bb8dfe6c959d95130fb010906","src/sys/ptrace/bsd.rs":"4c590d8f023ff52f396f8b6f2150c08e5c9486d3088d9c173db33a70d616b800","src/sys/ptrace/linux.rs":"b14114c4cbefd58f9df48e93e47d8f82992167942d4e683018cd31ceed184bc6","src/sys/ptrace/mod.rs":"3b5e4cc9cf447e989f40c73cb1951a4705322852009023c5a3d7e39ec1e9c39b","src/sys/quota.rs":"421ff70a0749dd0cea37a22a971bf3e9474f627bfa0e37874d9893787271996b","src/sys/reboot.rs":"eacdf57694a6629fb05787e16450446102a62818274495f2ad4e445807d09221","src/sys/resource.rs":"84eba41f288c97b4ab9060a6046d0d34e66a1f8e12655032c60a703280cca832","src/sys/select.rs":"2520086330bc1978a7db183bee92d96ba2711a4505839179a5f082ad555045b2","src/sys/sendfile.rs":"2075cea1ea5967b5de18e5cecb94bc041ff2675f7eb9e223051aa8a52dd8f733","src/sys/signal.rs":"39492bd9a98a48616a2f66a717def527574c6429251b533d8406d2b25cc2cb3f","src/sys/signalfd.rs":"af9eee01d712e48609fddf6b0ec332cd5f80b9940081b4c2e16cc338e959b5f3","src/sys/socket/addr.rs":"1b6f4e1ca16004cd5fa511264076b2c24ccc9cf3d7727157a0fabc62c47fe94a","src/sys/socket/mod.rs":"e65112b3b54905166b7a412fd9811e1e123c5eb1b3b46286937082fa6e86973d","src/sys/socket/sockopt.rs":"386bc08c0faf49a9d0ef99c70538c66b7d426d3deeb7b0ebedee1ef917d7bafc","src/sys/stat.rs":"3928598e6428d7e44b42d36aeb59ac353eaf0270801a6ac72c511804c5fdf358","src/sys/statfs.rs":"852c7e68c094ea8b1f978ee811c1e0bf6a38661c7a07114527697e7aae584dff","src/sys/statvfs.rs":"f699280f3ee2645ce39631d404355e7b49818849c4afa0bdf4f5020931cb1bef","src/sys/sysinfo.rs":"b4519b1ca091c9dbe94d2a6fd6304944bf3df5626973d2c6884022559706f0d9","src/sys/termios.rs":"7c0d9f4bc0062a510cf0f799264f807530c3d1e9e23a0d405d595f395ad7e01c","src/sys/time.rs":"c991d69a892cd7201c53d1399533e45802d581a1afa109016014aa9872d8db53","src/sys/timer.rs":"8c10f0e7cfac857ad00460be30bc68b957909cc9296e70718d3b5d4a0babafde","src/sys/timerfd.rs":"8958120030ed7bb58028b75e7e1829d4d231fa0da2c65f9335df7b7f1e0f6074","src/sys/uio.rs":"0ed960748eb4a85ce8f8413ab478d451f4460e85130cc3b803c85d72c057a529","src/sys/utsname.rs":"0cdda0cc111caaa0e4ebe2d4588bdc825d878e5bcb7a9136073b15f87a20e11f","src/sys/wait.rs":"c4c19ce13ea96c47fd51e227a1982d2aaafdb6b75edd726159848dd617f70da8","src/time.rs":"d4e0872361a57810837f5bd790cbca3a2b9db1ac4694a3c52d1564ad3532d3be","src/ucontext.rs":"b8f2e04757a9c2bc38c3b1e259d3a013da8a730fe9bfbe5487637395681b43d3","src/unistd.rs":"e9d24b6490d0578fc3e31200023e131df9471c09b7553b452a9ad76399eea753","test/common/mod.rs":"1d7e28e3635754664cd056f3a1079232ff5c118df619e1d0551a9972eb0b3cd6","test/sys/mod.rs":"87b2891d83067ff21f72b8ff7fde3019dc45b6877282ac278b6da151de45c7a7","test/sys/test_aio.rs":"ea9c0af6632739439d7f8187d2c82aeca7ac177d817210815b1a3edcd7a84e9b","test/sys/test_aio_drop.rs":"614070155fa16a979b7341d001639c5ce24a1d6f632c3abce45a5a6d49c4039b","test/sys/test_epoll.rs":"c30b08d665a1fe7d7a04fe51d50ec78fc74c2ac707ae0f95f82104d5c76ceaf2","test/sys/test_inotify.rs":"a141b9a995892547b51ceeb6761a70a6b86d37e8f38d13ea2c497b81b4b0f49f","test/sys/test_ioctl.rs":"00ccc5afb665e533a0a4b6d6a6be438bcaea19fce335390feef4e91d17b3036c","test/sys/test_mman.rs":"fe9019927ed3ca51d2d59d3305a53cc31797a1460044d24e2631f120c9289552","test/sys/test_prctl.rs":"9c3d0fb16a41c3fd80541b313c2bb63de75634ad4711a71af106e58b0cec9ea8","test/sys/test_pthread.rs":"ace36a2f5587f1874854281b4fd84e4e4d892a1e3c5cc38ced57975739522ad6","test/sys/test_ptrace.rs":"0385eebc8b1b8c72f655b745769decd9143ad83018198375982da0896310456b","test/sys/test_select.rs":"2843bc2484d51ba335567cc50bbc4eb6848ac6c6702ced42b177ffe04b49f7f3","test/sys/test_signal.rs":"19c267ffe9a37452719c2b030c62ab8e123d20e3f6ba4da6902375283e3b9593","test/sys/test_signalfd.rs":"0e1060143e2612c490bc3d0168d0bbb042ef55e3f1d91d2578b9e42e4310a14d","test/sys/test_socket.rs":"de724f58d1d703d28be1d4e35fd72df41f835082cdcb4fb579330d0be31dc74f","test/sys/test_sockopt.rs":"4a7fbb08719ae99803280f8af94e134ad90d92bf3ca4fbee0ef0ab398aadecea","test/sys/test_stat.rs":"6630a28217fd708bb84cd4f7e7101836b74f2420f9888923fdab664ccc331c1d","test/sys/test_sysinfo.rs":"ffd49bc96375914a2c4a4a59730cae8072f85771e2c4a80d3403df38d967e272","test/sys/test_termios.rs":"f38dfe45ab4ac9760b1d8c49e18da900d544927080a4a0bbb02b0c854c130455","test/sys/test_timerfd.rs":"cfed3abf58118611d08f6985251a7739cff67108e11214222a1d2394a3a026ce","test/sys/test_uio.rs":"90d973858f3e303c9fb99bc49d8d9a2e184be17e4e771cf3682af80b2ebd1533","test/sys/test_wait.rs":"6fd59fffeeb09ff620c359baefd062ba777598982b6cb001ccc07b6bc7605493","test/test.rs":"58a302e9055555806942c35e0edd0aaa63b2ebb3205c9a7e29491b726a5e2abe","test/test_clearenv.rs":"45ca548035b3c20ec87314715feaba2be973709a635d85b8cde46fd1d9f1ecd4","test/test_dir.rs":"ae3c11c58cb06da6557aa2a839c6653c54cd7724283fffe9df5a5d3feabdd89a","test/test_fcntl.rs":"7a23635451ed4a7b061cdc3015723c803c901e665e2beffde726b7f20ddf61d2","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":"7d04b7e0f0f56e8129a0e68a6a338d7d46fdedde863dae4732d3c899e7864c66","test/test_mq.rs":"84dffb2201e2a4bb19f476fa7c23bbc2615453d27e5b958d3841ff371b6faa81","test/test_net.rs":"f2912327ebb2a3d37e6cff02a5ac3106cf889cc5c74404db4ef0034059ba26f1","test/test_nix_path.rs":"01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b","test/test_nmount.rs":"d6c112547bb80968170b5497cda4b6cbf69dabec6f51d494bd52298995ceff18","test/test_poll.rs":"d6eef82848734e47cc9e1f1ce521e35587e63f69876baea660ef22eebc2b1ea6","test/test_pty.rs":"4184e446af7a365ead628596cd77ad168c835a5dea6abca3ee614d86a4412dda","test/test_resource.rs":"40aef790ab745cec31a4b333d2ca406b462aa9bdf4a6d3756371e498b8d51e9a","test/test_sched.rs":"c4579bd376fab8816e63b07fa9ace31dc08e63ebb7c855a2c450698090d1d1e8","test/test_sendfile.rs":"f7d52f6aa680b5667b966d5c046917ba43924e9b9fca6adbcf68479459e06366","test/test_stat.rs":"c407ca47a5258750076d041afad2f6add4c3563be36628bde1c5b314f5d0765d","test/test_time.rs":"f7a21b1e279e60e84909d5dadda97ded66d3326b131fe317badf9af0a1b50335","test/test_timer.rs":"3ae20d364f075d2811f3ff94eda9886682cc21d8807656007d2464fe36d1e361","test/test_unistd.rs":"3ef7b335639747b6d57a04c2264a38ad379b680cebc0b8d8b8e247610630e58a"},"package":"2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"}
\ No newline at end of file +{"files":{"CHANGELOG.md":"67c8efb2646c390f76029cf2fbb6205bd23e6e15c149ed32a1549e25bef1babe","Cargo.toml":"cd8795ba96b904a16c840e69c94b9493d8032b966579e4589b9adb35efdfec5a","LICENSE":"66e3ee1fa7f909ad3c612d556f2a0cdabcd809ad6e66f3b0605015ac64841b70","README.md":"de89eb5b6e00eff6eb3043475da16abf3ae63906cbe3103a450c4bf27cad3f3e","build.rs":"f4b3c533039fe39f167251372b4f378ebef43203654f0ac2340dc0e222206787","src/dir.rs":"10a6ff94e56b849ac8ea762905efa85d11812e5539587ce8e5cce932961c7141","src/env.rs":"9d1e7d52c6c5f46d790a8cbc6d5d2ff9097fb7728594c518d51824ebfb70c9b3","src/errno.rs":"204dd49244d461da6827142386a6b491aaeb6c4ca3760bbe9df5fd2f90e9f4ea","src/fcntl.rs":"1014853b9782285f1467dbe79cff435d0bb1d4122dca0b23d7872ddbeb7688c0","src/features.rs":"6edc53dbbadf56a193dc71053f6512b6cf0d09feb5efb8eb991877de1d70c43c","src/ifaddrs.rs":"40ed9c631b5bff403a697889971f44ad87d6fd6bebbd99cb047cf47c190ee87e","src/kmod.rs":"1e77141714fc7da27fcc59caaae0e31b5801f6e164a57f8d6d399a1b4051d5b1","src/lib.rs":"268b7ad111b99ceaf7c78a348824e8a2be84380bdfe8826e8378b6510eac6b9e","src/macros.rs":"ea6b3a5c117f82ab97d0a410501e7ec250ee11baf3c44b1f207ec404ea682d85","src/mount/bsd.rs":"47477e79ee2862b1d7a5afaf099884036fd81e6384624e60d5d2719a9ddbc112","src/mount/linux.rs":"57ada5949a7a393c427e8076e8556938104f70a73c51452d95ab3d78838f442b","src/mount/mod.rs":"8d8c51f25130e02c860f1d85959d02322b4d9ec748295dfc5a4544e6231725a0","src/mqueue.rs":"0c094b340c918796aff8aa43bc78da566c6203c779a41ce5f490fd41110628f1","src/net/if_.rs":"3d32aceb516606271d8edd2dffd5c710a11868aab54119aebec5a70b35cd963b","src/net/mod.rs":"577f70170e53d4a6de1abb70bf8f1031ec3e65c0e63ef5fcf05c907125e7ac17","src/poll.rs":"6d27611db0bc1a64bee80cc74155bb593b1e488092d753fdee102404e7e408ec","src/poll_timeout.rs":"c32412689fcafa561514df9d974206c11bb1276ef79fc10964f11b5416f51a00","src/pty.rs":"d30a7bb587bf727615fc505bc8987d5cae543be0d79d2a8f71a41d9cec2afb6e","src/sched.rs":"542bd9b1d8e1ed132c9a16c3485c70d3d47e30f702c4da1b39906fc64da4c308","src/sys/aio.rs":"b57cc89b70b1052c699264427661c293425536db9577f2fa2c6bdfc805fe06ae","src/sys/epoll.rs":"49ce070f560c8ac7a6f338b4b182f70049303c7d895320a7186fb98b666cafa9","src/sys/event.rs":"3e6e737a880f802644b7c5656a6579d747a66b595ba26ab6cb59df1141ac6eda","src/sys/eventfd.rs":"244ec41689cf90ba0527dd3501ea9f2623873b35cb66577dfc652c35e8492fe4","src/sys/fanotify.rs":"769282c558c7ceb3ea3f9661b6717d507641add46b8b033d4bd200c87df2a66d","src/sys/inotify.rs":"5ce6d83beb2f328c33acf0dd3639a1bdd7b5c2e362745b3cb0fa4c549a641e90","src/sys/ioctl/bsd.rs":"e6affc2babd4fa4539574426e416b330b7e32ba4fd2821899a67417261e7089e","src/sys/ioctl/linux.rs":"8c8bdfc239aa175efb4fc2f666a6ecc799b7d614f85e9143595fff05d37f76f0","src/sys/ioctl/mod.rs":"304a959e9eb24dccfd3fc6153719b417367d9208dc7e6859239fb020c407d103","src/sys/memfd.rs":"a7c2c446143f1dda5537a4342a84b83bb536072215ca973de71f87a33ed8bd37","src/sys/mman.rs":"e75b3ae89c18f541ba8fed01b9147661078f9d035eeb4eaf792ba0e4ff1167fe","src/sys/mod.rs":"30057a1c687859394f27581247ae9e412f5f68d4484bd5196797c1bc1939a6c7","src/sys/personality.rs":"f7fa4e97de0943aa6a969465ca7d2d69ac98015f7c339fdbb88d83ffe26db4ce","src/sys/prctl.rs":"785f97a545e010069d67ef11b22a70ca5000e131ee8ca990a2652a596ade77e5","src/sys/pthread.rs":"258cdf7ff0b61a4afa6d228109e4cb4fb88d859bb8dfe6c959d95130fb010906","src/sys/ptrace/bsd.rs":"54b92e1ffe6455a545f807ed7de9011be05251adfdc71a5823b1965579650939","src/sys/ptrace/linux.rs":"c347075fc8d9afd63d6eaf1acf84afb3a2c956b236eef9f17c19e883a6aaa73d","src/sys/ptrace/mod.rs":"a9aefa2b10cc63c8b40adcd3e7dd612a8f4677bf6f37420cdd09e7129ba02c95","src/sys/quota.rs":"1638e34bddd955c7f98f1814d239eb76647101295c8a1ae40c78dd7dd7638f20","src/sys/reboot.rs":"b748217e4877c94c1870885407b9ab1ab9e059c9fb7d04818a1b29477eac81c6","src/sys/resource.rs":"e701020b893666321f44c08df9e60f8927d00ac1035c89965e967dc0b44c6222","src/sys/select.rs":"9cfcb3a9d15a46b2f209e66cbaf136dab6894c711031313557bc58534ecedc70","src/sys/sendfile.rs":"fc7ac628424eb1132674c73bbe19f0d82a28d6752b0beffbf111965ea3885760","src/sys/signal.rs":"da1720190cdedc854649a525f2cd2556daec1c069d3fe32ad65c4302cca8efd9","src/sys/signalfd.rs":"f0b4d32e642a3a02d349b38d317a805eedc6e60e9e773f650fb0ee4ad7f655a7","src/sys/socket/addr.rs":"75d94b8404711b4ec08b44c3d43c7854f7cd9cf8e17665056dddaf6398d1df2a","src/sys/socket/mod.rs":"12c1a291648553516437bec168602fbebcae3d1ad657a7e55cd86f842db29d50","src/sys/socket/sockopt.rs":"69ab0440767e808c0fe2f2d269eae67653b4657e51b8fe356fab95b7ab26546a","src/sys/stat.rs":"074401a0b0fe74d9516640e0790fe67b7727213115accfdb331a9767ae20064c","src/sys/statfs.rs":"991370ce27196f8721a03a88c3b906cc248f46f147ebd6524d45c61433dc0239","src/sys/statvfs.rs":"526c2e69b640f49331e8ca7a2e59cdb803887c91a53fa41f866364fec93bce24","src/sys/sysinfo.rs":"b4519b1ca091c9dbe94d2a6fd6304944bf3df5626973d2c6884022559706f0d9","src/sys/termios.rs":"dd68b78e4a87786d22334c014d258e43d12f4e9370acda61209eb2c9ed176c86","src/sys/time.rs":"a63f6b5cf67a9323ccc3a225ffec88bb078c5dcf22d0eba78ae071db67aefc53","src/sys/timer.rs":"8c10f0e7cfac857ad00460be30bc68b957909cc9296e70718d3b5d4a0babafde","src/sys/timerfd.rs":"569d662725018427b517ffcfa78d8d03e150a344b8b8533d3f16e3bfd5c762da","src/sys/uio.rs":"d0886bf517e9b21af8ad6a25d332003fe9e132fed43cd642ec61b32d27622bd6","src/sys/utsname.rs":"e1f81d363621445633101800ba34debdb222eaf3a25553f8b486f74d49e4be41","src/sys/wait.rs":"338235d42a2ec29633cf64dada7b9b1d434ed0005776bffdecfd5c69922eed89","src/time.rs":"30038bbe683857469d106631cea13ee1e43f149cb4c947a8353824270ee4267c","src/ucontext.rs":"b8f2e04757a9c2bc38c3b1e259d3a013da8a730fe9bfbe5487637395681b43d3","src/unistd.rs":"5bb3b5ad2984793be4eed6adf653bbc52592c2459b9063009b92edb83ed562cf","test/common/mod.rs":"953155de9a50974fda7a43a66269211154bbb5898791e0abd97dc4184d482f23","test/sys/mod.rs":"f08046850a4b7a9bbf203d8eba0ee3ae9c32b6bd4d9c7bf52ca29efb3eb74f35","test/sys/test_aio.rs":"902ae4abda9286db551e65a7eccf267baee16eeefd1cdddac8399bef2ede0060","test/sys/test_aio_drop.rs":"e9e45333b24381bba99235372d5917a22fbd8692eddfbebcf519697c603de812","test/sys/test_epoll.rs":"c30b08d665a1fe7d7a04fe51d50ec78fc74c2ac707ae0f95f82104d5c76ceaf2","test/sys/test_event.rs":"be4b1b1abd25f87f00b3d115105ef832b2c654fd7028c42f1a304a935935b479","test/sys/test_fanotify.rs":"55b0917f8b85fdc8277e6a796d06251a39398b9f2da88d9eec98a763ff03e918","test/sys/test_inotify.rs":"a141b9a995892547b51ceeb6761a70a6b86d37e8f38d13ea2c497b81b4b0f49f","test/sys/test_ioctl.rs":"07d08a46c4ac84161974b655a0d040e03efc9338e7a7505e0d16826b7653b5c2","test/sys/test_mman.rs":"f129659d6995fcada15e7c923cb943d8dd4c6e4aaa141c6cc5bacfa3257793f5","test/sys/test_prctl.rs":"9c3d0fb16a41c3fd80541b313c2bb63de75634ad4711a71af106e58b0cec9ea8","test/sys/test_pthread.rs":"ace36a2f5587f1874854281b4fd84e4e4d892a1e3c5cc38ced57975739522ad6","test/sys/test_ptrace.rs":"ac4fff669bfc58955e94ed0171e4d47ecf2366fce62509c659e78192f9de7a6d","test/sys/test_resource.rs":"aa58f566efb8132b42ae98be6e50b72fee86ef50c4bcc4a7bf49b275f6762008","test/sys/test_select.rs":"09fe9d020e4f1cdb0951ebd27a6c3f408b23471ce2c51d2f1e4708500fc15261","test/sys/test_signal.rs":"ac6cbd345cbd93b1c9bead56794bd978dc44435beea921bedbdb8a2761e557d5","test/sys/test_signalfd.rs":"8db0c371d0cac7d68208505990291ebc2b2cb8671b0edba16ef22b6b9e56dab2","test/sys/test_socket.rs":"8c6190cbea80d5b2866d0891c6f44fddaba337b655af7e5628dc9537e1cbfab9","test/sys/test_sockopt.rs":"dd1839c495ce37535b2fbf78290dfbb1350f40ed7ed92c7fcedc16a88730ecf1","test/sys/test_stat.rs":"6630a28217fd708bb84cd4f7e7101836b74f2420f9888923fdab664ccc331c1d","test/sys/test_statfs.rs":"a32f6319ea7e989747707de27b06332e7942b07e07ab1602af408be91fae7e73","test/sys/test_statvfs.rs":"05cf8f1bcab0f0cd8fbefe8a2a72f9ac6d95aa760c355ac6d4b6f9c61649bc38","test/sys/test_sysinfo.rs":"ffd49bc96375914a2c4a4a59730cae8072f85771e2c4a80d3403df38d967e272","test/sys/test_termios.rs":"6c6897e0320d063a758f6702228c64ef2b459b4a5affa07ae7e76c1142432f0a","test/sys/test_time.rs":"aff97dd1bfc4aa9b616cc71e9cc11f25fb3ad983f1406c856648736847778c19","test/sys/test_timer.rs":"3ae20d364f075d2811f3ff94eda9886682cc21d8807656007d2464fe36d1e361","test/sys/test_timerfd.rs":"cfed3abf58118611d08f6985251a7739cff67108e11214222a1d2394a3a026ce","test/sys/test_uio.rs":"dda569818e3256ff45aa07b33cffb59828983c83b20266b864cdfa38103cffc9","test/sys/test_utsname.rs":"b8371dca02c9cdfc0c8e93df9b5cf5b5cb8a92b114977966854918abeb01ad73","test/sys/test_wait.rs":"c958e51b10a7d0396d0013e9d637a2848ad9d061d526408b40dfefb850c22beb","test/test.rs":"e1da3bf8ef929a9e4aca354bf72578f6649c80dd5f32400eb124b229bd4506f8","test/test_clearenv.rs":"45ca548035b3c20ec87314715feaba2be973709a635d85b8cde46fd1d9f1ecd4","test/test_dir.rs":"e6a100685f945b6007312d22575ac5e27363c649f3fed19fb10b18ac5d905449","test/test_errno.rs":"e7a1320e97350c2883368ffe9fc47fd041f4f9ecdee360d21d36254a63a305a3","test/test_fcntl.rs":"4467e1e8698256c982df17108dacd1fcb6ba0eda18044fe198eff25629827e66","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":"9fc453613eab116841a7f2ba57098eebec853fc16ce0e59cb459a203e006115b","test/test_mq.rs":"d8ec2a3f3acad4369851663b3f7fef03177d9f8395b585dee8e2c53f6a2a9b4a","test/test_net.rs":"cfa1d3b4e252193a4b119141f8e93d637e3c32e9029aef72f8bb83e00be6c3b5","test/test_nix_path.rs":"01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b","test/test_nmount.rs":"d6c112547bb80968170b5497cda4b6cbf69dabec6f51d494bd52298995ceff18","test/test_poll.rs":"25b4fa094bbcda5a5317a25d2f292465965dbe3e066374b04a9b27a8d55897ac","test/test_pty.rs":"ec54c5fe096396b5aed5677276acaf80b4c58be7222ee285cfd4eaadf7b34ce0","test/test_sched.rs":"c4579bd376fab8816e63b07fa9ace31dc08e63ebb7c855a2c450698090d1d1e8","test/test_sendfile.rs":"6f82e9f66359a85a7aa819ffd38c7c3326c1bb2384950d681085dc7823fc4a20","test/test_stat.rs":"dae37bd9b5e46e1a76696bed435d8bc4e98ecb91bb3476e7133a6197178d6644","test/test_time.rs":"6eb3536936c67bcfbc80a73a902b4a485943aab5375fc7e3880da6695a4eafce","test/test_unistd.rs":"828a990974b4d843d59f3d134758d4b6a9afa43da3d07dcaf314fcc1615bd732"},"package":"ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4"}
\ No newline at end of file diff --git a/third_party/rust/nix/CHANGELOG.md b/third_party/rust/nix/CHANGELOG.md index 3a171afd68..37e4ab2d4c 100644 --- a/third_party/rust/nix/CHANGELOG.md +++ b/third_party/rust/nix/CHANGELOG.md @@ -1,8 +1,205 @@ -# Change Log - All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/). +# Change Log + +## [0.28.0] - 2024-02-24 + + +### Added + +- Added `mkdtemp` wrapper ([#1297](https://github.com/nix-rust/nix/pull/1297)) +- Add associated constants `UTIME_OMIT` `UTIME_NOW` for `TimeSpec` + ([#1879](https://github.com/nix-rust/nix/pull/1879)) +- Added `EventFd` type. ([#1945](https://github.com/nix-rust/nix/pull/1945)) +- - Added `impl From<Signal> for SigSet`. + - Added `impl std::ops::BitOr for SigSet`. + - Added `impl std::ops::BitOr for Signal`. + - Added `impl std::ops::BitOr<Signal> for SigSet` + + ([#1959](https://github.com/nix-rust/nix/pull/1959)) +- Added `TlsGetRecordType` control message type and corresponding enum for + linux ([#2065](https://github.com/nix-rust/nix/pull/2065)) +- Added `Ipv6HopLimit` to `::nix::sys::socket::ControlMessage` for Linux, + MacOS, FreeBSD, DragonflyBSD, Android, iOS and Haiku. + ([#2074](https://github.com/nix-rust/nix/pull/2074)) +- Added `Icmp` and `IcmpV6` to `SockProtocol` + ([#2103](https://github.com/nix-rust/nix/pull/2103)) +- Added rfork support for FreeBSD in `unistd` + ([#2121](https://github.com/nix-rust/nix/pull/2121)) +- Added `MapFlags::map_hugetlb_with_size_log2` method for Linux targets + ([#2125](https://github.com/nix-rust/nix/pull/2125)) +- Added `mmap_anonymous` function + ([#2127](https://github.com/nix-rust/nix/pull/2127)) +- Added `mips32r6` and `mips64r6` support for signal, ioctl and ptrace + ([#2138](https://github.com/nix-rust/nix/pull/2138)) +- Added `F_GETPATH` FcntlFlags entry on Apple/NetBSD/DragonflyBSD for + `::nix::fcntl`. ([#2142](https://github.com/nix-rust/nix/pull/2142)) +- Added `F_KINFO` FcntlFlags entry on FreeBSD for `::nix::fcntl`. + ([#2152](https://github.com/nix-rust/nix/pull/2152)) +- Added `F_GETPATH_NOFIRMLINK` and `F_BARRIERFSYNC` FcntlFlags entry + on Apple for `::nix::fcntl`. + ([#2155](https://github.com/nix-rust/nix/pull/2155)) +- Added newtype `Flock` to automatically unlock a held flock upon drop. + Added `Flockable` trait to represent valid types for `Flock`. + ([#2170](https://github.com/nix-rust/nix/pull/2170)) +- Added `SetSockOpt` impls to enable Linux Kernel TLS on a TCP socket and to + import TLS parameters. ([#2175](https://github.com/nix-rust/nix/pull/2175)) +- - Added the `::nix::sys::socket::SocketTimestamp` enum for configuring the + `TsClock` (a.k.a `SO_TS_CLOCK`) sockopt + - Added FreeBSD's `ScmRealtime` and `ScmMonotonic` as new options in + `::nix::sys::socket::ControlMessageOwned` + + ([#2187](https://github.com/nix-rust/nix/pull/2187)) +- Added new fanotify API: wrappers for `fanotify_init` and `fanotify_mark` + ([#2194](https://github.com/nix-rust/nix/pull/2194)) +- Added `SpecialCharacterindices` support for haiku. + ([#2195](https://github.com/nix-rust/nix/pull/2195)) +- Added `sys::sendfile` support for solaris/illumos. + ([#2198](https://github.com/nix-rust/nix/pull/2198)) +- impl Display for InterfaceFlags + ([#2206](https://github.com/nix-rust/nix/pull/2206)) +- Added `sendfilev` in sys::sendfile for solarish + ([#2207](https://github.com/nix-rust/nix/pull/2207)) +- Added `fctrl::SealFlag::F_SEAL_FUTURE_WRITE` + ([#2213](https://github.com/nix-rust/nix/pull/2213)) +- Added `Ipv6MulticastHops` as socket option to set and read. + ([#2234](https://github.com/nix-rust/nix/pull/2234)) +- Enable `ControlMessageOwned::Ipv4RecvIf` and + `ControlMessageOwned::Ipv4RecvDstAddr` for DragonFlyBSD + ([#2240](https://github.com/nix-rust/nix/pull/2240)) +- `ClockId::set_time()` and `time::clock_settime()` are now enabled on macOS + ([#2241](https://github.com/nix-rust/nix/pull/2241)) +- Added `IpBindAddressNoPort` sockopt to support `IP_BIND_ADDRESS_NO_PORT` + available on linux. ([#2244](https://github.com/nix-rust/nix/pull/2244)) +- Enable `MapFlags::map_hugetlb_with_size_log2` method for Android/Fuchsia + ([#2245](https://github.com/nix-rust/nix/pull/2245)) +- Added `TcpFastOpenConnect` sockopt to support `TCP_FASTOPEN_CONNECT` + available on linux. ([#2247](https://github.com/nix-rust/nix/pull/2247)) +- Add `reboot(2)` for OpenBSD/NetBSD + ([#2251](https://github.com/nix-rust/nix/pull/2251)) +- Added new `MemFdCreateFlag` constants to `sys::memfd` on Linux and Android + related to hugetlbfs support. + ([#2252](https://github.com/nix-rust/nix/pull/2252)) +- Expose the inner fd of `Kqueue` through: + + * impl AsFd for Kqueue + * impl From\<Kqueue\> for OwnedFd + + ([#2258](https://github.com/nix-rust/nix/pull/2258)) +- Added `sys::eventfd` support on FreeBSD + ([#2259](https://github.com/nix-rust/nix/pull/2259)) +- Added `MmapFlags::MAP_FIXED` constant in `sys::mman` for netbsd and openbsd + ([#2260](https://github.com/nix-rust/nix/pull/2260)) +- Added the `SO_LISTENQLIMIT` sockopt. + ([#2263](https://github.com/nix-rust/nix/pull/2263)) +- Enable the `AT_EMPTY_PATH` flag for the `fchownat()` function + ([#2267](https://github.com/nix-rust/nix/pull/2267)) +- Add `AtFlags::AT_EMPTY_PATH` for FreeBSD and Hurd + ([#2270](https://github.com/nix-rust/nix/pull/2270)) +- Enable `OFlag::O_DIRECTORY for Solarish + ([#2275](https://github.com/nix-rust/nix/pull/2275)) +- Added the `Backlog` wrapper type for the `listen` call. + ([#2276](https://github.com/nix-rust/nix/pull/2276)) +- Add `clock_nanosleep()` ([#2277](https://github.com/nix-rust/nix/pull/2277)) +- Enabled `O_DIRECT` in `fcntl::OFlags` for solarish + ([#2278](https://github.com/nix-rust/nix/pull/2278)) +- Added a new API sigsuspend. + ([#2279](https://github.com/nix-rust/nix/pull/2279)) +- - Added `errno::Errno::set` function + - Added `errno::Errno::set_raw` function + - Added `errno::Errno::last_raw` function + - Added `errno::Errno::from_raw` function + + ([#2283](https://github.com/nix-rust/nix/pull/2283)) +- Enable the `AT_EMPTY_PATH` flag for the `linkat()` function + ([#2284](https://github.com/nix-rust/nix/pull/2284)) +- Enable unistd::{sync, syncfs} for Android + ([#2296](https://github.com/nix-rust/nix/pull/2296)) + +### Changed + +- `poll` now takes `PollTimeout` replacing `libc::c_int`. + ([#1876](https://github.com/nix-rust/nix/pull/1876)) +- Deprecated `sys::eventfd::eventfd`. + ([#1945](https://github.com/nix-rust/nix/pull/1945)) +- `mmap`, `mmap_anonymous`, `munmap`, `mremap`, `madvise`, `msync`, `mprotect`, + `munlock` and `mlock` updated to use `NonNull`. + ([#2000](https://github.com/nix-rust/nix/pull/2000)) +- `mmap` function now accepts `F` instead of `Option<F>` + ([#2127](https://github.com/nix-rust/nix/pull/2127)) +- `PollFd::new` now takes a `BorrowedFd` argument, with relaxed lifetime + requirements relative to the previous version. + ([#2134](https://github.com/nix-rust/nix/pull/2134)) +- `FdSet::{insert, remove, contains}` now take `BorrowedFd` arguments, and have + relaxed lifetime requirements relative to 0.27.1. + ([#2136](https://github.com/nix-rust/nix/pull/2136)) +- The following APIs now take an implementation of `AsFd` rather than a + `RawFd`: + + - `unistd::tcgetpgrp` + - `unistd::tcsetpgrp` + - `unistd::fpathconf` + - `unistd::ttyname` + - `unistd::getpeereid` ([#2137](https://github.com/nix-rust/nix/pull/2137)) +- Changed `openat()` and `Dir::openat()`, now take optional `dirfd`s + ([#2139](https://github.com/nix-rust/nix/pull/2139)) +- The MSRV is now 1.69 ([#2144](https://github.com/nix-rust/nix/pull/2144)) +- Changed function `SockaddrIn::ip()` to return `net::Ipv4Addr` and refactored + `SocketAddrV6::ip()` to be `const` + ([#2151](https://github.com/nix-rust/nix/pull/2151)) +- The following APIs now take optional `dirfd`s: + + - `readlinkat()` + - `fstatat()` + - `mknodat()` + - `mkdirat()` + - `execveat()` + + ([#2157](https://github.com/nix-rust/nix/pull/2157)) +- `Epoll::wait` now takes `EpollTimeout` replacing `isize`. + ([#2202](https://github.com/nix-rust/nix/pull/2202)) +- - Deprecated `errno::errno()` function (use `Errno::last_raw()`) + - Deprecated `errno::from_i32()` function (use `Errno::from_raw()`) + - Deprecated `errno::Errno::from_i32()` function (use `Errno::from_raw()`) + + ([#2283](https://github.com/nix-rust/nix/pull/2283)) + +### Fixed + +- Fix `SigSet` incorrect implementation of `Eq`, `PartialEq` and `Hash` + ([#1946](https://github.com/nix-rust/nix/pull/1946)) +- Fixed `::sys::socket::sockopt::IpMulticastTtl` by fixing the value of optlen + passed to `libc::setsockopt` and added tests. + ([#2072](https://github.com/nix-rust/nix/pull/2072)) +- Fixed the function signature of `recvmmsg`, potentially causing UB + ([#2119](https://github.com/nix-rust/nix/pull/2119)) +- Fix `SignalFd::set_mask`. In 0.27.0 it would actually close the file + descriptor. ([#2141](https://github.com/nix-rust/nix/pull/2141)) +- Fixed UnixAddr::new for haiku, it did not record the `sun_len` value as + needed. + Fixed `sys::socket::addr::from_raw_parts` and + `sys::socket::Sockaddrlike::len` build for solaris. + ([#2242](https://github.com/nix-rust/nix/pull/2242)) +- Fixed solaris build globally. + ([#2248](https://github.com/nix-rust/nix/pull/2248)) +- Changed the `dup3` wrapper to perform a real call to `dup3` instead of + emulating it via `dup2` and `fcntl` to get rid of race condition + ([#2268](https://github.com/nix-rust/nix/pull/2268)) +- Fixed `::unistd::Group::members` using read_unaligned to avoid crash on + misaligned pointers ([#2311](https://github.com/nix-rust/nix/pull/2311)) + +### Removed + +- The `FchownatFlags` type has been deprecated, please use `AtFlags` instead. + ([#2267](https://github.com/nix-rust/nix/pull/2267)) +- Removed the `dup3` wrapper on macOS, which was emulated via `dup2` and + `fcntl` and could cause a race condition. The `dup3` system call is not + supported on macOS. ([#2268](https://github.com/nix-rust/nix/pull/2268)) +- The `LinkatFlags` type has been deprecated, please use `AtFlags` instead. + ([#2284](https://github.com/nix-rust/nix/pull/2284)) + + ## [0.27.1] - 2023-08-28 ### Fixed @@ -99,7 +296,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [0.26.3] - 2023-08-27 ### Fixed -- Fix: send `ETH_P_ALL` in htons format +- Fix: send `ETH_P_ALL` in htons format ([#1925](https://github.com/nix-rust/nix/pull/1925)) - Fix: `recvmsg` now sets the length of the received `sockaddr_un` field correctly on Linux platforms. ([#2041](https://github.com/nix-rust/nix/pull/2041)) @@ -187,7 +384,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ([#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. diff --git a/third_party/rust/nix/Cargo.toml b/third_party/rust/nix/Cargo.toml index bb04ab2702..34bc897c54 100644 --- a/third_party/rust/nix/Cargo.toml +++ b/third_party/rust/nix/Cargo.toml @@ -11,11 +11,12 @@ [package] edition = "2021" -rust-version = "1.65" +rust-version = "1.69" name = "nix" -version = "0.27.1" +version = "0.28.0" authors = ["The nix-rust Project Developers"] include = [ + "build.rs", "src/**/*", "test/**/*", "LICENSE", @@ -61,11 +62,6 @@ name = "test-clearenv" path = "test/test_clearenv.rs" [[test]] -name = "test-mount" -path = "test/test_mount.rs" -harness = false - -[[test]] name = "test-prctl" path = "test/sys/test_prctl.rs" @@ -76,7 +72,7 @@ version = "2.3.1" version = "1.0" [dependencies.libc] -version = "0.2.147" +version = "0.2.153" features = ["extra_traits"] [dependencies.memoffset] @@ -102,6 +98,9 @@ version = "1.0.7" [dev-dependencies.tempfile] version = "3.7.1" +[build-dependencies.cfg_aliases] +version = "0.1.1" + [features] acct = [] aio = ["pin-utils"] @@ -109,6 +108,7 @@ default = [] dir = ["fs"] env = [] event = [] +fanotify = [] feature = [] fs = [] hostname = [] diff --git a/third_party/rust/nix/README.md b/third_party/rust/nix/README.md index e172de2750..fb9f84ca44 100644 --- a/third_party/rust/nix/README.md +++ b/third_party/rust/nix/README.md @@ -2,6 +2,7 @@ [![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) +[![maintenance-status](https://img.shields.io/badge/maintenance-looking--for--maintainer-orange.svg)](https://github.com/nix-rust/nix/issues/2132) [Documentation (Releases)](https://docs.rs/nix/) @@ -98,13 +99,14 @@ The following targets are supported by `nix`: <li>x86_64-unknown-linux-gnux32</li> <li>x86_64-unknown-openbsd</li> <li>x86_64-unknown-redox</li> + <li>i686-unknown-hurd-gnu</li> </td> </tr> </table> ## Minimum Supported Rust Version (MSRV) -nix is supported on Rust 1.65 and higher. Its MSRV will not be +nix is supported on Rust 1.69 and higher. Its MSRV will not be changed in the future without bumping the major or minor version. ## Contributing diff --git a/third_party/rust/nix/build.rs b/third_party/rust/nix/build.rs new file mode 100644 index 0000000000..4535af1f04 --- /dev/null +++ b/third_party/rust/nix/build.rs @@ -0,0 +1,25 @@ +use cfg_aliases::cfg_aliases; + +fn main() { + cfg_aliases! { + android: { target_os = "android" }, + dragonfly: { target_os = "dragonfly" }, + ios: { target_os = "ios" }, + freebsd: { target_os = "freebsd" }, + illumos: { target_os = "illumos" }, + linux: { target_os = "linux" }, + macos: { target_os = "macos" }, + netbsd: { target_os = "netbsd" }, + openbsd: { target_os = "openbsd" }, + solaris: { target_os = "solaris" }, + watchos: { target_os = "watchos" }, + tvos: { target_os = "tvos" }, + + apple_targets: { any(ios, macos, watchos, tvos) }, + bsd: { any(freebsd, dragonfly, netbsd, openbsd, apple_targets) }, + linux_android: { any(android, linux) }, + freebsdlike: { any(dragonfly, freebsd) }, + netbsdlike: { any(netbsd, openbsd) }, + solarish: { any(illumos, solaris) }, + } +} diff --git a/third_party/rust/nix/src/dir.rs b/third_party/rust/nix/src/dir.rs index 96a5843bc6..ab70f064cc 100644 --- a/third_party/rust/nix/src/dir.rs +++ b/third_party/rust/nix/src/dir.rs @@ -44,7 +44,7 @@ impl Dir { /// Opens the given path as with `fcntl::openat`. pub fn openat<P: ?Sized + NixPath>( - dirfd: RawFd, + dirfd: Option<RawFd>, path: &P, oflag: OFlag, mode: sys::stat::Mode, @@ -225,16 +225,13 @@ impl Entry { pub fn ino(&self) -> u64 { cfg_if! { if #[cfg(any(target_os = "aix", - 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"))] { + target_os = "hurd", + solarish, + linux_android, + apple_targets))] { self.0.d_ino as u64 } else { u64::from(self.0.d_fileno) @@ -253,12 +250,7 @@ impl Entry { /// 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 = "aix", - target_os = "illumos", - target_os = "solaris", - target_os = "haiku" - )))] + #[cfg(not(any(solarish, target_os = "aix", target_os = "haiku")))] match self.0.d_type { libc::DT_FIFO => Some(Type::Fifo), libc::DT_CHR => Some(Type::CharacterDevice), @@ -271,12 +263,7 @@ impl Entry { } // illumos, Solaris, and Haiku systems do not have the d_type member at all: - #[cfg(any( - target_os = "aix", - target_os = "illumos", - target_os = "solaris", - target_os = "haiku" - ))] + #[cfg(any(solarish, target_os = "aix", target_os = "haiku"))] None } } diff --git a/third_party/rust/nix/src/env.rs b/third_party/rust/nix/src/env.rs index 95177a1d2a..510bbb0924 100644 --- a/third_party/rust/nix/src/env.rs +++ b/third_party/rust/nix/src/env.rs @@ -40,13 +40,12 @@ impl std::error::Error for ClearEnvError {} /// thread safety must still be upheld. pub unsafe fn clearenv() -> std::result::Result<(), ClearEnvError> { cfg_if! { - if #[cfg(any(target_os = "fuchsia", + if #[cfg(any(linux_android, + target_os = "fuchsia", target_os = "wasi", target_env = "uclibc", - target_os = "linux", - target_os = "android", target_os = "emscripten"))] { - let ret = libc::clearenv(); + let ret = unsafe { libc::clearenv() }; } else { use std::env; for (name, _) in env::vars_os() { diff --git a/third_party/rust/nix/src/errno.rs b/third_party/rust/nix/src/errno.rs index 50b35248f8..2e74a84454 100644 --- a/third_party/rust/nix/src/errno.rs +++ b/third_party/rust/nix/src/errno.rs @@ -1,74 +1,127 @@ +//! Safe wrappers around errno functions +//! +//! # Example +//! ``` +//! use nix::errno::Errno; +//! +//! Errno::EIO.set(); +//! assert_eq!(Errno::last(), Errno::EIO); +//! +//! Errno::clear(); +//! assert_eq!(Errno::last(), Errno::from_raw(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"))] { + apple_targets,))] { unsafe fn errno_location() -> *mut c_int { - libc::__error() + unsafe { libc::__error() } } - } else if #[cfg(any(target_os = "android", - target_os = "netbsd", - target_os = "openbsd"))] { + } else if #[cfg(any(target_os = "android", netbsdlike))] { unsafe fn errno_location() -> *mut c_int { - libc::__errno() + unsafe { libc::__errno() } } } else if #[cfg(any(target_os = "linux", target_os = "redox", target_os = "dragonfly", - target_os = "fuchsia"))] { + target_os = "fuchsia", + target_os = "hurd"))] { unsafe fn errno_location() -> *mut c_int { - libc::__errno_location() + unsafe { libc::__errno_location() } } - } else if #[cfg(any(target_os = "illumos", target_os = "solaris"))] { + } else if #[cfg(solarish)] { unsafe fn errno_location() -> *mut c_int { - libc::___errno() + unsafe { libc::___errno() } } } else if #[cfg(any(target_os = "haiku",))] { unsafe fn errno_location() -> *mut c_int { - libc::_errnop() + unsafe { libc::_errnop() } } } else if #[cfg(any(target_os = "aix"))] { unsafe fn errno_location() -> *mut c_int { - libc::_Errno() + unsafe { libc::_Errno() } } } } -/// 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 +#[deprecated(since = "0.28.0", note = "please use `Errno::last_raw()` instead")] pub fn errno() -> i32 { - unsafe { *errno_location() } + Errno::last_raw() } impl Errno { + /// Returns the current value of errno pub fn last() -> Self { - last() + Self::from_raw(Self::last_raw()) } - pub fn desc(self) -> &'static str { - desc(self) + /// Returns the current raw i32 value of errno + pub fn last_raw() -> i32 { + unsafe { *errno_location() } + } + + /// Sets the value of errno. + /// + /// # Example + /// ``` + /// use nix::errno::Errno; + /// + /// Errno::EIO.set(); + /// + /// assert_eq!(Errno::last(), Errno::EIO); + /// ``` + pub fn set(self) { + Self::set_raw(self as i32) } + /// Sets the raw i32 value of errno. + pub fn set_raw(errno: i32) { + // Safe because errno is a thread-local variable + unsafe { + *errno_location() = errno; + } + } + + #[deprecated( + since = "0.28.0", + note = "please use `Errno::from_raw()` instead" + )] pub const fn from_i32(err: i32) -> Errno { + Self::from_raw(err) + } + + pub const fn from_raw(err: i32) -> Errno { + #[allow(deprecated)] from_i32(err) } + pub fn desc(self) -> &'static str { + desc(self) + } + + /// Sets the platform-specific errno to no-error + /// + /// ``` + /// use nix::errno::Errno; + /// + /// Errno::EIO.set(); + /// + /// Errno::clear(); + /// + /// let err = Errno::last(); + /// assert_ne!(err, Errno::EIO); + /// assert_eq!(err, Errno::from_raw(0)); + /// ``` pub fn clear() { - clear() + Self::set_raw(0) } /// Returns `Ok(value)` if it does not contain the sentinel value. This @@ -137,14 +190,10 @@ 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) + ioerror.raw_os_error().map(Errno::from_raw).ok_or(ioerror) } } -fn last() -> Errno { - Errno::from_i32(errno()) -} - fn desc(errno: Errno) -> &'static str { use self::Errno::*; match errno { @@ -225,467 +274,270 @@ fn desc(errno: Errno) -> &'static str { EHOSTUNREACH => "No route to host", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, + solarish, target_os = "aix", - target_os = "illumos", - target_os = "solaris", target_os = "fuchsia" ))] ECHRNG => "Channel number out of range", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, + solarish, target_os = "aix", - target_os = "illumos", - target_os = "solaris", target_os = "fuchsia" ))] EL2NSYNC => "Level 2 not synchronized", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, + solarish, target_os = "aix", - target_os = "illumos", - target_os = "solaris", target_os = "fuchsia" ))] EL3HLT => "Level 3 halted", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, + solarish, target_os = "aix", - target_os = "illumos", - target_os = "solaris", target_os = "fuchsia" ))] EL3RST => "Level 3 reset", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, + solarish, target_os = "aix", - target_os = "illumos", - target_os = "solaris", target_os = "fuchsia" ))] ELNRNG => "Link number out of range", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, + solarish, target_os = "aix", - target_os = "illumos", - target_os = "solaris", target_os = "fuchsia" ))] EUNATCH => "Protocol driver not attached", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, + solarish, target_os = "aix", - target_os = "illumos", - target_os = "solaris", target_os = "fuchsia" ))] ENOCSI => "No CSI structure available", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, + solarish, target_os = "aix", - 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" - ))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] EBADE => "Invalid exchange", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] EBADR => "Invalid request descriptor", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] EXFULL => "Exchange full", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] ENOANO => "No anode", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] EBADRQC => "Invalid request code", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] EBADSLT => "Invalid slot", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, solarish, 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" + linux_android, + solarish, + target_os = "fuchsia", + target_os = "hurd" ))] ENOSTR => "Device not a stream", #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" + linux_android, + solarish, + target_os = "fuchsia", + target_os = "hurd" ))] ENODATA => "No data available", #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" + linux_android, + solarish, + target_os = "fuchsia", + target_os = "hurd" ))] ETIME => "Timer expired", #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" + linux_android, + solarish, + target_os = "fuchsia", + target_os = "hurd" ))] ENOSR => "Out of streams resources", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, solarish, 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" - ))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] ENOPKG => "Package not installed", #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" + linux_android, + solarish, + target_os = "fuchsia", + target_os = "hurd" ))] EREMOTE => "Object is remote", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, + solarish, target_os = "aix", - 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" - ))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] EADV => "Advertise error", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] ESRMNT => "Srmount error", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] ECOMM => "Communication error on send", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, + solarish, target_os = "aix", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" + target_os = "fuchsia", ))] EPROTO => "Protocol error", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, + solarish, target_os = "aix", - target_os = "illumos", - target_os = "solaris", target_os = "fuchsia" ))] EMULTIHOP => "Multihop attempted", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, target_os = "fuchsia"))] EDOTDOT => "RFS specific error", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "aix", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, target_os = "aix", target_os = "fuchsia"))] EBADMSG => "Not a data message", - #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg(solarish)] EBADMSG => "Trying to read unreadable message", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, target_os = "aix", target_os = "fuchsia", - target_os = "haiku" + target_os = "haiku", + target_os = "hurd" ))] 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" - ))] + #[cfg(any(linux_android, solarish, 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" - ))] + #[cfg(any(linux_android, solarish, 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" - ))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] EREMCHG => "Remote address changed", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, solarish, 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" - ))] + #[cfg(any(linux_android, solarish, 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" - ))] + #[cfg(any(linux_android, solarish, 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" - ))] + #[cfg(any(linux_android, solarish, 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" + linux_android, + solarish, + target_os = "fuchsia", + target_os = "hurd" ))] ELIBEXEC => "Cannot exec a shared library directly", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, + solarish, target_os = "aix", - target_os = "illumos", - target_os = "solaris", target_os = "fuchsia", target_os = "openbsd" ))] EILSEQ => "Illegal byte sequence", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, + solarish, target_os = "aix", - 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" - ))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] ESTRPIPE => "Streams pipe error", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "illumos", - target_os = "solaris", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] EUSERS => "Too many users", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_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" - ))] + #[cfg(any(linux_android, target_os = "fuchsia", target_os = "hurd"))] ESTALE => "Stale file handle", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, target_os = "fuchsia"))] EUCLEAN => "Structure needs cleaning", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, target_os = "fuchsia"))] ENOTNAM => "Not a XENIX named type file", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, target_os = "fuchsia"))] ENAVAIL => "No XENIX semaphores available", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, target_os = "fuchsia"))] EISNAM => "Is a named type file", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, target_os = "fuchsia"))] EREMOTEIO => "Remote I/O error", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, target_os = "fuchsia"))] EDQUOT => "Quota exceeded", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, target_os = "fuchsia", target_os = "openbsd", target_os = "dragonfly" @@ -693,71 +545,47 @@ fn desc(errno: Errno) -> &'static str { ENOMEDIUM => "No medium found", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_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", + linux_android, + solarish, target_os = "fuchsia", target_os = "haiku" ))] ECANCELED => "Operation canceled", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, target_os = "fuchsia"))] ENOKEY => "Required key not available", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, target_os = "fuchsia"))] EKEYEXPIRED => "Key has expired", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, target_os = "fuchsia"))] EKEYREVOKED => "Key has been revoked", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, target_os = "fuchsia"))] EKEYREJECTED => "Key was rejected by service", #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, target_os = "aix", - target_os = "fuchsia" + target_os = "fuchsia", + target_os = "hurd" ))] EOWNERDEAD => "Owner died", - #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg(solarish)] EOWNERDEAD => "Process died with lock", - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "aix", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, target_os = "aix", target_os = "fuchsia"))] ENOTRECOVERABLE => "State not recoverable", - #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg(solarish)] ENOTRECOVERABLE => "Lock is not recoverable", #[cfg(any( @@ -772,21 +600,13 @@ fn desc(errno: Errno) -> &'static str { ))] EHWPOISON => "Memory page has hardware error", - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg(freebsdlike)] EDOOFUS => "Programming error", - #[cfg(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "redox" - ))] + #[cfg(any(freebsdlike, target_os = "hurd", target_os = "redox"))] EMULTIHOP => "Multihop attempted", - #[cfg(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "redox" - ))] + #[cfg(any(freebsdlike, target_os = "hurd", target_os = "redox"))] ENOLINK => "Link has been severed", #[cfg(target_os = "freebsd")] @@ -795,300 +615,157 @@ fn desc(errno: Errno) -> &'static str { #[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" - ))] + #[cfg(any(bsd, target_os = "hurd"))] 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" - ))] + #[cfg(any(bsd, target_os = "redox", solarish))] EOVERFLOW => "Value too large to be stored in data type", #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", + freebsdlike, + apple_targets, target_os = "netbsd", target_os = "redox", - target_os = "haiku" + target_os = "haiku", + target_os = "hurd" ))] 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" - ))] + #[cfg(any(bsd, 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", + bsd, target_os = "redox", - target_os = "haiku" + target_os = "haiku", + target_os = "hurd" ))] 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" + bsd, + target_os = "haiku", + target_os = "hurd", + target_os = "redox" ))] EPROTO => "Protocol error", #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd" + freebsdlike, + apple_targets, + target_os = "openbsd", + target_os = "hurd" ))] ENOTRECOVERABLE => "State not recoverable", - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd" - ))] + #[cfg(any(freebsdlike, apple_targets, 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", + bsd, target_os = "aix", - target_os = "illumos", - target_os = "solaris", - target_os = "haiku" + solarish, + target_os = "haiku", + target_os = "hurd" ))] ENOTSUP => "Operation not supported", - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "aix", - target_os = "openbsd", - target_os = "netbsd" - ))] + #[cfg(any(bsd, target_os = "aix", target_os = "hurd"))] EPROCLIM => "Too many processes", #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", + bsd, target_os = "aix", - target_os = "openbsd", - target_os = "netbsd", + target_os = "hurd", 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", + bsd, + solarish, target_os = "redox", target_os = "aix", - target_os = "illumos", - target_os = "solaris", - target_os = "haiku" + target_os = "haiku", + target_os = "hurd" ))] EDQUOT => "Disc quota exceeded", #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd", + bsd, + solarish, target_os = "redox", target_os = "aix", - 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 = "aix", - target_os = "openbsd", - target_os = "netbsd", - target_os = "redox" - ))] + #[cfg(any(bsd, target_os = "aix", 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" - ))] + #[cfg(any(bsd, target_os = "hurd"))] 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" - ))] + #[cfg(any(bsd, target_os = "hurd"))] ERPCMISMATCH => "RPC version wrong", - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd" - ))] + #[cfg(any(bsd, target_os = "hurd"))] 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" - ))] + #[cfg(any(bsd, target_os = "hurd"))] EPROGMISMATCH => "Program version wrong", - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "openbsd", - target_os = "netbsd" - ))] + #[cfg(any(bsd, target_os = "hurd"))] 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" - ))] + #[cfg(any(bsd, target_os = "hurd"))] 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" - ))] + #[cfg(any(bsd, target_os = "hurd"))] EAUTH => "Authentication error", #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", + bsd, target_os = "aix", - target_os = "openbsd", - target_os = "netbsd", + target_os = "hurd", target_os = "redox" ))] ECANCELED => "Operation canceled", - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] EPWROFF => "Device power is off", - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] EDEVERR => "Device error, e.g. paper out", - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] EBADEXEC => "Bad executable", - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] EBADARCH => "Bad CPU type in executable", - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] ESHLIBVERS => "Shared library version mismatch", - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] EBADMACHO => "Malformed Macho file", - #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "netbsd", - target_os = "haiku" - ))] + #[cfg(any(apple_targets, target_os = "netbsd", target_os = "haiku"))] EMULTIHOP => "Reserved", #[cfg(any( - target_os = "macos", - target_os = "ios", + apple_targets, target_os = "aix", 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" - ))] + #[cfg(any(apple_targets, target_os = "netbsd", target_os = "haiku"))] ENOLINK => "Reserved", #[cfg(any( - target_os = "macos", - target_os = "ios", + apple_targets, target_os = "aix", target_os = "netbsd", target_os = "redox" @@ -1096,8 +773,7 @@ fn desc(errno: Errno) -> &'static str { ENOSR => "No STREAM resources", #[cfg(any( - target_os = "macos", - target_os = "ios", + apple_targets, target_os = "aix", target_os = "netbsd", target_os = "redox" @@ -1105,30 +781,23 @@ fn desc(errno: Errno) -> &'static str { ENOSTR => "Not a STREAM", #[cfg(any( - target_os = "macos", - target_os = "ios", + apple_targets, target_os = "aix", target_os = "netbsd", target_os = "redox" ))] ETIME => "STREAM ioctl timeout", - #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "aix", - target_os = "illumos", - target_os = "solaris" - ))] + #[cfg(any(apple_targets, solarish, target_os = "aix"))] EOPNOTSUPP => "Operation not supported on socket", - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] ENOPOLICY => "No such policy registered", - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] EQFULL => "Interface output queue is full", - #[cfg(target_os = "openbsd")] + #[cfg(any(target_os = "openbsd", target_os = "hurd"))] EOPNOTSUPP => "Operation not supported", #[cfg(target_os = "openbsd")] @@ -1137,18 +806,33 @@ fn desc(errno: Errno) -> &'static str { #[cfg(target_os = "dragonfly")] EASYNC => "Async", - #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg(solarish)] EDEADLOCK => "Resource deadlock would occur", - #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg(solarish)] ELOCKUNMAPPED => "Locked lock was unmapped", - #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg(solarish)] ENOTACTIVE => "Facility is not active", + + #[cfg(target_os = "hurd")] + EBACKGROUND => "Inappropriate operation for background process", + + #[cfg(target_os = "hurd")] + EDIED => "Translator died", + + #[cfg(target_os = "hurd")] + EGREGIOUS => "You really blew it this time", + + #[cfg(target_os = "hurd")] + EIEIO => "Computer bought the farm", + + #[cfg(target_os = "hurd")] + EGRATUITOUS => "Gratuitous error", } } -#[cfg(any(target_os = "linux", target_os = "android", target_os = "fuchsia"))] +#[cfg(any(linux_android, target_os = "fuchsia"))] mod consts { #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[repr(i32)] @@ -1296,6 +980,10 @@ mod consts { pub const ENOTSUP: Errno = Errno::EOPNOTSUPP; } + #[deprecated( + since = "0.28.0", + note = "please use `Errno::from_raw()` instead" + )] pub const fn from_i32(e: i32) -> Errno { use self::Errno::*; @@ -1438,7 +1126,7 @@ mod consts { } } -#[cfg(any(target_os = "macos", target_os = "ios"))] +#[cfg(apple_targets)] mod consts { #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[repr(i32)] @@ -1559,6 +1247,10 @@ mod consts { pub const EDEADLOCK: Errno = Errno::EDEADLK; } + #[deprecated( + since = "0.28.0", + note = "please use `Errno::from_raw()` instead" + )] pub const fn from_i32(e: i32) -> Errno { use self::Errno::*; @@ -1786,6 +1478,10 @@ mod consts { pub const EOPNOTSUPP: Errno = Errno::ENOTSUP; } + #[deprecated( + since = "0.28.0", + note = "please use `Errno::from_raw()` instead" + )] pub const fn from_i32(e: i32) -> Errno { use self::Errno::*; @@ -2003,6 +1699,10 @@ mod consts { pub const EOPNOTSUPP: Errno = Errno::ENOTSUP; } + #[deprecated( + since = "0.28.0", + note = "please use `Errno::from_raw()` instead" + )] pub const fn from_i32(e: i32) -> Errno { use self::Errno::*; @@ -2215,6 +1915,10 @@ mod consts { pub const EWOULDBLOCK: Errno = Errno::EAGAIN; } + #[deprecated( + since = "0.28.0", + note = "please use `Errno::from_raw()` instead" + )] pub const fn from_i32(e: i32) -> Errno { use self::Errno::*; @@ -2429,6 +2133,10 @@ mod consts { pub const EWOULDBLOCK: Errno = Errno::EAGAIN; } + #[deprecated( + since = "0.28.0", + note = "please use `Errno::from_raw()` instead" + )] pub const fn from_i32(e: i32) -> Errno { use self::Errno::*; @@ -2632,6 +2340,10 @@ mod consts { pub const EWOULDBLOCK: Errno = Errno::EAGAIN; } + #[deprecated( + since = "0.28.0", + note = "please use `Errno::from_raw()` instead" + )] pub const fn from_i32(e: i32) -> Errno { use self::Errno::*; @@ -2726,7 +2438,7 @@ mod consts { } } -#[cfg(any(target_os = "illumos", target_os = "solaris"))] +#[cfg(solarish)] mod consts { #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[repr(i32)] @@ -2861,6 +2573,10 @@ mod consts { pub const EWOULDBLOCK: Errno = Errno::EAGAIN; } + #[deprecated( + since = "0.28.0", + note = "please use `Errno::from_raw()` instead" + )] pub const fn from_i32(e: i32) -> Errno { use self::Errno::*; @@ -3081,6 +2797,10 @@ mod consts { pub const EOPNOTSUPP: Errno = Errno::ENOTSUP; } + #[deprecated( + since = "0.28.0", + note = "please use `Errno::from_raw()` instead" + )] pub const fn from_i32(e: i32) -> Errno { use self::Errno::*; @@ -3272,6 +2992,10 @@ mod consts { EOPNOTSUPP = libc::EOPNOTSUPP, } + #[deprecated( + since = "0.28.0", + note = "please use `Errno::from_raw()` instead" + )] pub const fn from_i32(e: i32) -> Errno { use self::Errno::*; @@ -3378,3 +3102,235 @@ mod consts { } } } + +#[cfg(target_os = "hurd")] +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, + EMFILE = libc::EMFILE, + ENFILE = libc::ENFILE, + 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, + 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, + EDESTADDRREQ = libc::EDESTADDRREQ, + 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, + EFTYPE = libc::EFTYPE, + EAUTH = libc::EAUTH, + ENEEDAUTH = libc::ENEEDAUTH, + ENOSYS = libc::ENOSYS, + ELIBEXEC = libc::ELIBEXEC, + ENOTSUP = libc::ENOTSUP, + EILSEQ = libc::EILSEQ, + EBACKGROUND = libc::EBACKGROUND, + EDIED = libc::EDIED, + EGREGIOUS = libc::EGREGIOUS, + EIEIO = libc::EIEIO, + EGRATUITOUS = libc::EGRATUITOUS, + EBADMSG = libc::EBADMSG, + EIDRM = libc::EIDRM, + EMULTIHOP = libc::EMULTIHOP, + ENODATA = libc::ENODATA, + ENOLINK = libc::ENOLINK, + ENOMSG = libc::ENOMSG, + ENOSR = libc::ENOSR, + ENOSTR = libc::ENOSTR, + EOVERFLOW = libc::EOVERFLOW, + EPROTO = libc::EPROTO, + ETIME = libc::ETIME, + ECANCELED = libc::ECANCELED, + EOWNERDEAD = libc::EOWNERDEAD, + ENOTRECOVERABLE = libc::ENOTRECOVERABLE, + } + + impl Errno { + pub const EWOULDBLOCK: Errno = Errno::EAGAIN; + } + + #[deprecated( + since = "0.28.0", + note = "please use `Errno::from_raw()` instead" + )] + 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::EMFILE => EMFILE, + libc::ENFILE => ENFILE, + 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::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::EDESTADDRREQ => EDESTADDRREQ, + 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::EFTYPE => EFTYPE, + libc::EAUTH => EAUTH, + libc::ENEEDAUTH => ENEEDAUTH, + libc::ENOSYS => ENOSYS, + libc::ELIBEXEC => ELIBEXEC, + libc::ENOTSUP => ENOTSUP, + libc::EILSEQ => EILSEQ, + libc::EBACKGROUND => EBACKGROUND, + libc::EDIED => EDIED, + libc::EGREGIOUS => EGREGIOUS, + libc::EIEIO => EIEIO, + libc::EGRATUITOUS => EGRATUITOUS, + libc::EBADMSG => EBADMSG, + libc::EIDRM => EIDRM, + libc::EMULTIHOP => EMULTIHOP, + libc::ENODATA => ENODATA, + libc::ENOLINK => ENOLINK, + libc::ENOMSG => ENOMSG, + libc::ENOSR => ENOSR, + libc::ENOSTR => ENOSTR, + libc::EOVERFLOW => EOVERFLOW, + libc::EPROTO => EPROTO, + libc::ETIME => ETIME, + libc::ECANCELED => ECANCELED, + libc::EOWNERDEAD => EOWNERDEAD, + libc::ENOTRECOVERABLE => ENOTRECOVERABLE, + _ => UnknownErrno, + } + } +} diff --git a/third_party/rust/nix/src/fcntl.rs b/third_party/rust/nix/src/fcntl.rs index 9bfecda5ac..ccefe955de 100644 --- a/third_party/rust/nix/src/fcntl.rs +++ b/third_party/rust/nix/src/fcntl.rs @@ -1,27 +1,39 @@ +//! file control options use crate::errno::Errno; -use libc::{self, c_char, c_int, c_uint, size_t, ssize_t}; +#[cfg(all(target_os = "freebsd", target_arch = "x86_64"))] +use core::slice; +use libc::{c_int, c_uint, size_t, ssize_t}; +#[cfg(any( + target_os = "netbsd", + apple_targets, + target_os = "dragonfly", + all(target_os = "freebsd", target_arch = "x86_64"), +))] +use std::ffi::CStr; use std::ffi::OsString; +#[cfg(not(any(target_os = "redox", target_os = "solaris")))] +use std::ops::{Deref, DerefMut}; #[cfg(not(target_os = "redox"))] use std::os::raw; use std::os::unix::ffi::OsStringExt; use std::os::unix::io::RawFd; -// For splice and copy_file_range +#[cfg(not(any(target_os = "redox", target_os = "solaris")))] +use std::os::unix::io::{AsRawFd, OwnedFd}; #[cfg(any( - target_os = "android", - target_os = "freebsd", - target_os = "linux" + target_os = "netbsd", + apple_targets, + target_os = "dragonfly", + all(target_os = "freebsd", target_arch = "x86_64"), ))] -use std::{ - os::unix::io::{AsFd, AsRawFd}, - ptr, -}; +use std::path::PathBuf; +#[cfg(any(linux_android, target_os = "freebsd"))] +use std::{os::unix::io::AsFd, ptr}; #[cfg(feature = "fs")] use crate::{sys::stat::Mode, NixPath, Result}; #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, target_os = "emscripten", target_os = "fuchsia", target_os = "wasi", @@ -32,41 +44,58 @@ use crate::{sys::stat::Mode, NixPath, Result}; pub use self::posix_fadvise::{posix_fadvise, PosixFadviseAdvice}; #[cfg(not(target_os = "redox"))] -#[cfg(any(feature = "fs", feature = "process"))] +#[cfg(any(feature = "fs", feature = "process", feature = "user"))] libc_bitflags! { + /// Flags that control how the various *at syscalls behave. #[cfg_attr(docsrs, doc(cfg(any(feature = "fs", feature = "process"))))] pub struct AtFlags: c_int { + #[allow(missing_docs)] + #[doc(hidden)] + // Should not be used by the public API, but only internally. AT_REMOVEDIR; + /// Used with [`linkat`](crate::unistd::linkat`) to create a link to a symbolic link's + /// target, instead of to the symbolic link itself. AT_SYMLINK_FOLLOW; + /// Used with functions like [`fstatat`](crate::sys::stat::fstatat`) to operate on a link + /// itself, instead of the symbolic link's target. AT_SYMLINK_NOFOLLOW; - #[cfg(any(target_os = "android", target_os = "linux"))] + /// Don't automount the terminal ("basename") component of pathname if it is a directory + /// that is an automount point. + #[cfg(linux_android)] AT_NO_AUTOMOUNT; - #[cfg(any(target_os = "android", target_os = "linux"))] + /// If the provided path is an empty string, operate on the provided directory file + /// descriptor instead. + #[cfg(any(linux_android, target_os = "freebsd", target_os = "hurd"))] AT_EMPTY_PATH; + /// Used with [`faccessat`](crate::unistd::faccessat), the checks for accessibility are + /// performed using the effective user and group IDs instead of the real user and group ID #[cfg(not(target_os = "android"))] AT_EACCESS; } } -#[cfg(any(feature = "fs", feature = "term"))] +#[cfg(any( + feature = "fs", + feature = "term", + all(feature = "fanotify", target_os = "linux") +))] libc_bitflags!( /// Configuration options for opened files. - #[cfg_attr(docsrs, doc(cfg(any(feature = "fs", feature = "term"))))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "fs", feature = "term", all(feature = "fanotify", target_os = "linux")))))] 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 = "aix", - target_os = "illumos", - target_os = "solaris", - target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(not(any( + solarish, + target_os = "aix", + target_os = "haiku" + )))] O_ASYNC; /// Closes the file descriptor once an `execve` call is made. /// @@ -75,68 +104,42 @@ libc_bitflags!( /// 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())))] + #[cfg(any( + freebsdlike, + linux_android, + solarish, + target_os = "netbsd" + ))] 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())))] + #[cfg(any(linux_android, apple_targets, netbsdlike))] 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())))] + #[cfg(any(bsd, target_os = "redox"))] 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", + #[cfg(any(bsd, + all(target_os = "linux", not(target_env = "musl"), not(target_env = "ohos")), 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())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] 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; @@ -144,13 +147,11 @@ libc_bitflags!( 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())))] + #[cfg(any(linux_android, target_os = "redox"))] O_PATH; /// Only allow reading. /// @@ -161,36 +162,24 @@ libc_bitflags!( /// 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())))] + #[cfg(any(target_os = "linux", netbsdlike))] 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())))] + #[cfg(any(bsd, target_os = "redox"))] 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())))] + #[cfg(linux_android)] 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. /// @@ -199,9 +188,23 @@ libc_bitflags!( } ); +/// Computes the raw fd consumed by a function of the form `*at`. +#[cfg(any( + all(feature = "fs", not(target_os = "redox")), + all(feature = "process", linux_android), + all(feature = "fanotify", target_os = "linux") +))] +pub(crate) fn at_rawfd(fd: Option<RawFd>) -> raw::c_int { + fd.unwrap_or(libc::AT_FDCWD) +} + feature! { #![feature = "fs"] +/// open or create a file for reading, writing or executing +/// +/// # See Also +/// [`open`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html) // The conversion is not identical on all operating systems. #[allow(clippy::useless_conversion)] pub fn open<P: ?Sized + NixPath>( @@ -216,21 +219,37 @@ pub fn open<P: ?Sized + NixPath>( Errno::result(fd) } +/// open or create a file for reading, writing or executing +/// +/// The `openat` function is equivalent to the [`open`] function except in the case where the path +/// specifies a relative path. In that case, the file to be opened is determined relative to the +/// directory associated with the file descriptor `fd`. +/// +/// # See Also +/// [`openat`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/openat.html) // 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, + dirfd: Option<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) + libc::openat(at_rawfd(dirfd), cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint) })?; Errno::result(fd) } +/// Change the name of a file. +/// +/// The `renameat` function is equivalent to `rename` except in the case where either `old_path` +/// or `new_path` specifies a relative path. In such cases, the file to be renamed (or the its new +/// name, respectively) is located relative to `old_dirfd` or `new_dirfd`, respectively +/// +/// # See Also +/// [`renameat`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/rename.html) #[cfg(not(target_os = "redox"))] pub fn renameat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>( old_dirfd: Option<RawFd>, @@ -255,16 +274,30 @@ pub fn renameat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>( #[cfg(all(target_os = "linux", target_env = "gnu"))] #[cfg(feature = "fs")] libc_bitflags! { + /// Flags for use with [`renameat2`]. #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] pub struct RenameFlags: u32 { + /// Atomically exchange `old_path` and `new_path`. RENAME_EXCHANGE; + /// Don't overwrite `new_path` of the rename. Return an error if `new_path` already + /// exists. RENAME_NOREPLACE; + /// creates a "whiteout" object at the source of the rename at the same time as performing + /// the rename. + /// + /// This operation makes sense only for overlay/union filesystem implementations. RENAME_WHITEOUT; } } feature! { #![feature = "fs"] +/// Like [`renameat`], but with an additional `flags` argument. +/// +/// A `renameat2` call with an empty flags argument is equivalent to `renameat`. +/// +/// # See Also +/// * [`rename`](https://man7.org/linux/man-pages/man2/rename.2.html) #[cfg(all(target_os = "linux", target_env = "gnu"))] pub fn renameat2<P1: ?Sized + NixPath, P2: ?Sized + NixPath>( old_dirfd: Option<RawFd>, @@ -306,12 +339,12 @@ fn readlink_maybe_at<P: ?Sized + NixPath>( Some(dirfd) => libc::readlinkat( dirfd, cstr.as_ptr(), - v.as_mut_ptr() as *mut c_char, + v.as_mut_ptr().cast(), v.capacity() as size_t, ), None => libc::readlink( cstr.as_ptr(), - v.as_mut_ptr() as *mut c_char, + v.as_mut_ptr().cast(), v.capacity() as size_t, ), } @@ -322,7 +355,11 @@ fn inner_readlink<P: ?Sized + NixPath>( dirfd: Option<RawFd>, path: &P, ) -> Result<OsString> { - let mut v = Vec::with_capacity(libc::PATH_MAX as usize); + #[cfg(not(target_os = "hurd"))] + const PATH_MAX: usize = libc::PATH_MAX as usize; + #[cfg(target_os = "hurd")] + const PATH_MAX: usize = 1024; // Hurd does not define a hard limit, so try a guess first + let mut v = Vec::with_capacity(PATH_MAX); { // simple case: result is strictly less than `PATH_MAX` @@ -340,7 +377,7 @@ fn inner_readlink<P: ?Sized + NixPath>( let reported_size = match dirfd { #[cfg(target_os = "redox")] Some(_) => unreachable!(), - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(any(linux_android, target_os = "freebsd", target_os = "hurd"))] Some(dirfd) => { let flags = if path.is_empty() { AtFlags::AT_EMPTY_PATH @@ -348,18 +385,19 @@ fn inner_readlink<P: ?Sized + NixPath>( AtFlags::empty() }; super::sys::stat::fstatat( - dirfd, + Some(dirfd), path, flags | AtFlags::AT_SYMLINK_NOFOLLOW, ) } #[cfg(not(any( - target_os = "android", - target_os = "linux", - target_os = "redox" + linux_android, + target_os = "redox", + target_os = "freebsd", + target_os = "hurd" )))] Some(dirfd) => super::sys::stat::fstatat( - dirfd, + Some(dirfd), path, AtFlags::AT_SYMLINK_NOFOLLOW, ), @@ -375,7 +413,7 @@ fn inner_readlink<P: ?Sized + NixPath>( } else { // If lstat doesn't cooperate, or reports an error, be a little less // precise. - (libc::PATH_MAX as usize).max(128) << 1 + PATH_MAX.max(128) << 1 } }; @@ -400,29 +438,32 @@ fn inner_readlink<P: ?Sized + NixPath>( } } +/// Read value of a symbolic link +/// +/// # See Also +/// * [`readlink`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/readlink.html) pub fn readlink<P: ?Sized + NixPath>(path: &P) -> Result<OsString> { inner_readlink(None, path) } +/// Read value of a symbolic link. +/// +/// Equivalent to [`readlink` ] except where `path` specifies a relative path. In that case, +/// interpret `path` relative to open file specified by `dirfd`. +/// +/// # See Also +/// * [`readlink`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/readlink.html) #[cfg(not(target_os = "redox"))] pub fn readlinkat<P: ?Sized + NixPath>( - dirfd: RawFd, + dirfd: Option<RawFd>, path: &P, ) -> Result<OsString> { + let dirfd = at_rawfd(dirfd); 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(any(linux_android, target_os = "freebsd"))] #[cfg(feature = "fs")] libc_bitflags!( /// Additional flags for file sealing, which allows for limiting operations on a file. @@ -436,6 +477,10 @@ libc_bitflags!( F_SEAL_GROW; /// The file contents cannot be modified. F_SEAL_WRITE; + /// The file contents cannot be modified, except via shared writable mappings that were + /// created prior to the seal being set. Since Linux 5.1. + #[cfg(linux_android)] + F_SEAL_FUTURE_WRITE; } ); @@ -452,59 +497,105 @@ libc_bitflags!( feature! { #![feature = "fs"] +/// Commands for use with [`fcntl`]. #[cfg(not(target_os = "redox"))] #[derive(Debug, Eq, Hash, PartialEq)] #[non_exhaustive] pub enum FcntlArg<'a> { + /// Duplicate the provided file descriptor F_DUPFD(RawFd), + /// Duplicate the provided file descriptor and set the `FD_CLOEXEC` flag on it. F_DUPFD_CLOEXEC(RawFd), + /// Get the close-on-exec flag associated with the file descriptor F_GETFD, + /// Set the close-on-exec flag associated with the file descriptor F_SETFD(FdFlag), // FD_FLAGS + /// Get descriptor status flags F_GETFL, + /// Set descriptor status flags F_SETFL(OFlag), // O_NONBLOCK + /// Set or clear a file segment lock F_SETLK(&'a libc::flock), + /// Like [`F_SETLK`](FcntlArg::F_SETLK) except that if a shared or exclusive lock is blocked by + /// other locks, the process waits until the request can be satisfied. F_SETLKW(&'a libc::flock), + /// Get the first lock that blocks the lock description F_GETLK(&'a mut libc::flock), - #[cfg(any(target_os = "linux", target_os = "android"))] + /// Acquire or release an open file description lock + #[cfg(linux_android)] F_OFD_SETLK(&'a libc::flock), - #[cfg(any(target_os = "linux", target_os = "android"))] + /// Like [`F_OFD_SETLK`](FcntlArg::F_OFD_SETLK) except that if a conflicting lock is held on + /// the file, then wait for that lock to be released. + #[cfg(linux_android)] F_OFD_SETLKW(&'a libc::flock), - #[cfg(any(target_os = "linux", target_os = "android"))] + /// Determine whether it would be possible to create the given lock. If not, return details + /// about one existing lock that would prevent it. + #[cfg(linux_android)] F_OFD_GETLK(&'a mut libc::flock), + /// Add seals to the file #[cfg(any( - target_os = "android", - target_os = "linux", + linux_android, target_os = "freebsd" ))] F_ADD_SEALS(SealFlag), + /// Get seals associated with the file #[cfg(any( - target_os = "android", - target_os = "linux", + linux_android, target_os = "freebsd" ))] F_GET_SEALS, - #[cfg(any(target_os = "macos", target_os = "ios"))] + /// Asks the drive to flush all buffered data to permanent storage. + #[cfg(apple_targets)] F_FULLFSYNC, - #[cfg(any(target_os = "linux", target_os = "android"))] + /// fsync + issue barrier to drive + #[cfg(apple_targets)] + F_BARRIERFSYNC, + /// Return the capacity of a pipe + #[cfg(linux_android)] F_GETPIPE_SZ, - #[cfg(any(target_os = "linux", target_os = "android"))] + /// Change the capacity of a pipe + #[cfg(linux_android)] F_SETPIPE_SZ(c_int), + /// Look up the path of an open file descriptor, if possible. + #[cfg(any( + target_os = "netbsd", + target_os = "dragonfly", + apple_targets, + ))] + F_GETPATH(&'a mut PathBuf), + /// Look up the path of an open file descriptor, if possible. + #[cfg(all(target_os = "freebsd", target_arch = "x86_64"))] + F_KINFO(&'a mut PathBuf), + /// Return the full path without firmlinks of the fd. + #[cfg(apple_targets)] + F_GETPATH_NOFIRMLINK(&'a mut PathBuf), // TODO: Rest of flags } +/// Commands for use with [`fcntl`]. #[cfg(target_os = "redox")] #[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)] #[non_exhaustive] pub enum FcntlArg { + /// Duplicate the provided file descriptor F_DUPFD(RawFd), + /// Duplicate the provided file descriptor and set the `FD_CLOEXEC` flag on it. F_DUPFD_CLOEXEC(RawFd), + /// Get the close-on-exec flag associated with the file descriptor F_GETFD, + /// Set the close-on-exec flag associated with the file descriptor F_SETFD(FdFlag), // FD_FLAGS + /// Get descriptor status flags F_GETFL, + /// Set descriptor status flags F_SETFL(OFlag), // O_NONBLOCK } pub use self::FcntlArg::*; +/// Perform various operations on open file descriptors. +/// +/// # See Also +/// * [`fcntl`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fcntl.html) // TODO: Figure out how to handle value fcntl returns pub fn fcntl(fd: RawFd, arg: FcntlArg) -> Result<c_int> { let res = unsafe { @@ -523,51 +614,95 @@ pub fn fcntl(fd: RawFd, arg: FcntlArg) -> Result<c_int> { 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"))] + #[cfg(linux_android)] F_OFD_SETLK(flock) => libc::fcntl(fd, libc::F_OFD_SETLK, flock), - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] F_OFD_SETLKW(flock) => libc::fcntl(fd, libc::F_OFD_SETLKW, flock), - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] F_OFD_GETLK(flock) => libc::fcntl(fd, libc::F_OFD_GETLK, flock), #[cfg(any( - target_os = "android", - target_os = "linux", + linux_android, target_os = "freebsd" ))] F_ADD_SEALS(flag) => { libc::fcntl(fd, libc::F_ADD_SEALS, flag.bits()) } #[cfg(any( - target_os = "android", - target_os = "linux", + linux_android, target_os = "freebsd" ))] F_GET_SEALS => libc::fcntl(fd, libc::F_GET_SEALS), - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] F_FULLFSYNC => libc::fcntl(fd, libc::F_FULLFSYNC), - #[cfg(any(target_os = "linux", target_os = "android"))] + #[cfg(apple_targets)] + F_BARRIERFSYNC => libc::fcntl(fd, libc::F_BARRIERFSYNC), + #[cfg(linux_android)] F_GETPIPE_SZ => libc::fcntl(fd, libc::F_GETPIPE_SZ), - #[cfg(any(target_os = "linux", target_os = "android"))] + #[cfg(linux_android)] F_SETPIPE_SZ(size) => libc::fcntl(fd, libc::F_SETPIPE_SZ, size), + #[cfg(any( + target_os = "dragonfly", + target_os = "netbsd", + apple_targets, + ))] + F_GETPATH(path) => { + let mut buffer = vec![0; libc::PATH_MAX as usize]; + let res = libc::fcntl(fd, libc::F_GETPATH, buffer.as_mut_ptr()); + let ok_res = Errno::result(res)?; + let optr = CStr::from_bytes_until_nul(&buffer).unwrap(); + *path = PathBuf::from(OsString::from(optr.to_str().unwrap())); + return Ok(ok_res) + }, + #[cfg(all(target_os = "freebsd", target_arch = "x86_64"))] + F_KINFO(path) => { + let mut info: libc::kinfo_file = std::mem::zeroed(); + info.kf_structsize = std::mem::size_of::<libc::kinfo_file>() as i32; + let res = libc::fcntl(fd, libc::F_KINFO, &mut info); + let ok_res = Errno::result(res)?; + let p = info.kf_path; + let u8_slice = slice::from_raw_parts(p.as_ptr().cast(), p.len()); + let optr = CStr::from_bytes_until_nul(u8_slice).unwrap(); + *path = PathBuf::from(OsString::from(optr.to_str().unwrap())); + return Ok(ok_res) + }, + #[cfg(apple_targets)] + F_GETPATH_NOFIRMLINK(path) => { + let mut buffer = vec![0; libc::PATH_MAX as usize]; + let res = libc::fcntl(fd, libc::F_GETPATH_NOFIRMLINK, buffer.as_mut_ptr()); + let ok_res = Errno::result(res)?; + let optr = CStr::from_bytes_until_nul(&buffer).unwrap(); + *path = PathBuf::from(OsString::from(optr.to_str().unwrap())); + return Ok(ok_res) + }, } }; Errno::result(res) } -// TODO: convert to libc_enum +/// Operations for use with [`Flock::lock`]. +#[cfg(not(any(target_os = "redox", target_os = "solaris")))] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[non_exhaustive] pub enum FlockArg { + /// shared file lock LockShared, + /// exclusive file lock LockExclusive, + /// Unlock file Unlock, + /// Shared lock. Do not block when locking. LockSharedNonblock, + /// Exclusive lock. Do not block when locking. LockExclusiveNonblock, + #[allow(missing_docs)] + #[deprecated(since = "0.28.0", note = "Use FlockArg::Unlock instead")] UnlockNonblock, } +#[allow(missing_docs)] #[cfg(not(any(target_os = "redox", target_os = "solaris")))] +#[deprecated(since = "0.28.0", note = "`fcntl::Flock` should be used instead.")] pub fn flock(fd: RawFd, arg: FlockArg) -> Result<()> { use self::FlockArg::*; @@ -582,15 +717,133 @@ pub fn flock(fd: RawFd, arg: FlockArg) -> Result<()> { LockExclusiveNonblock => { libc::flock(fd, libc::LOCK_EX | libc::LOCK_NB) } + #[allow(deprecated)] UnlockNonblock => libc::flock(fd, libc::LOCK_UN | libc::LOCK_NB), } }; Errno::result(res).map(drop) } + +/// Represents valid types for flock. +/// +/// # Safety +/// Types implementing this must not be `Clone`. +#[cfg(not(any(target_os = "redox", target_os = "solaris")))] +pub unsafe trait Flockable: AsRawFd {} + +/// Represents an owned flock, which unlocks on drop. +/// +/// See [flock(2)](https://linux.die.net/man/2/flock) for details on locking semantics. +#[cfg(not(any(target_os = "redox", target_os = "solaris")))] +#[derive(Debug)] +pub struct Flock<T: Flockable>(T); + +#[cfg(not(any(target_os = "redox", target_os = "solaris")))] +impl<T: Flockable> Drop for Flock<T> { + fn drop(&mut self) { + let res = Errno::result(unsafe { libc::flock(self.0.as_raw_fd(), libc::LOCK_UN) }); + if res.is_err() && !std::thread::panicking() { + panic!("Failed to remove flock: {}", res.unwrap_err()); + } + } +} + +#[cfg(not(any(target_os = "redox", target_os = "solaris")))] +impl<T: Flockable> Deref for Flock<T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} +#[cfg(not(any(target_os = "redox", target_os = "solaris")))] +impl<T: Flockable> DerefMut for Flock<T> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +#[cfg(not(any(target_os = "redox", target_os = "solaris")))] +impl<T: Flockable> Flock<T> { + /// Obtain a/an flock. + /// + /// # Example + /// ``` + /// # use std::io::Write; + /// # use std::fs::File; + /// # use nix::fcntl::{Flock, FlockArg}; + /// # fn do_stuff(file: File) { + /// let mut file = match Flock::lock(file, FlockArg::LockExclusive) { + /// Ok(l) => l, + /// Err(_) => return, + /// }; + /// + /// // Do stuff + /// let data = "Foo bar"; + /// _ = file.write(data.as_bytes()); + /// _ = file.sync_data(); + /// # } + pub fn lock(t: T, args: FlockArg) -> std::result::Result<Self, (T, Errno)> { + let flags = match args { + FlockArg::LockShared => libc::LOCK_SH, + FlockArg::LockExclusive => libc::LOCK_EX, + FlockArg::LockSharedNonblock => libc::LOCK_SH | libc::LOCK_NB, + FlockArg::LockExclusiveNonblock => libc::LOCK_EX | libc::LOCK_NB, + #[allow(deprecated)] + FlockArg::Unlock | FlockArg::UnlockNonblock => return Err((t, Errno::EINVAL)), + }; + match Errno::result(unsafe { libc::flock(t.as_raw_fd(), flags) }) { + Ok(_) => Ok(Self(t)), + Err(errno) => Err((t, errno)), + } + } + + /// Remove the lock and return the object wrapped within. + /// + /// # Example + /// ``` + /// # use std::fs::File; + /// # use nix::fcntl::{Flock, FlockArg}; + /// fn do_stuff(file: File) -> nix::Result<()> { + /// let mut lock = match Flock::lock(file, FlockArg::LockExclusive) { + /// Ok(l) => l, + /// Err((_,e)) => return Err(e), + /// }; + /// + /// // Do critical section + /// + /// // Unlock + /// let file = match lock.unlock() { + /// Ok(f) => f, + /// Err((_, e)) => return Err(e), + /// }; + /// + /// // Do anything else + /// + /// Ok(()) + /// } + pub fn unlock(self) -> std::result::Result<T, (Self, Errno)> { + let inner = unsafe { match Errno::result(libc::flock(self.0.as_raw_fd(), libc::LOCK_UN)) { + Ok(_) => std::ptr::read(&self.0), + Err(errno) => return Err((self, errno)), + }}; + + std::mem::forget(self); + Ok(inner) + } +} + +// Safety: `File` is not [std::clone::Clone]. +#[cfg(not(any(target_os = "redox", target_os = "solaris")))] +unsafe impl Flockable for std::fs::File {} + +// Safety: `OwnedFd` is not [std::clone::Clone]. +#[cfg(not(any(target_os = "redox", target_os = "solaris")))] +unsafe impl Flockable for OwnedFd {} } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[cfg(feature = "zerocopy")] libc_bitflags! { /// Additional flags to `splice` and friends. @@ -636,7 +889,7 @@ feature! { // Note: FreeBSD defines the offset argument as "off_t". Linux and Android // define it as "loff_t". But on both OSes, on all supported platforms, those // are 64 bits. So Nix uses i64 to make the docs simple and consistent. -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +#[cfg(any(linux_android, target_os = "freebsd"))] pub fn copy_file_range<Fd1: AsFd, Fd2: AsFd>( fd_in: Fd1, off_in: Option<&mut i64>, @@ -669,7 +922,7 @@ pub fn copy_file_range<Fd1: AsFd, Fd2: AsFd>( let ret = unsafe { libc::syscall( libc::SYS_copy_file_range, - fd_in, + fd_in.as_fd().as_raw_fd(), off_in, fd_out.as_fd().as_raw_fd(), off_out, @@ -682,7 +935,11 @@ pub fn copy_file_range<Fd1: AsFd, Fd2: AsFd>( Errno::result(ret).map(|r| r as usize) } -#[cfg(any(target_os = "linux", target_os = "android"))] +/// Splice data to/from a pipe +/// +/// # See Also +/// *[`splice`](https://man7.org/linux/man-pages/man2/splice.2.html) +#[cfg(linux_android)] pub fn splice( fd_in: RawFd, off_in: Option<&mut libc::loff_t>, @@ -704,7 +961,11 @@ pub fn splice( Errno::result(ret).map(|r| r as usize) } -#[cfg(any(target_os = "linux", target_os = "android"))] +/// Duplicate pipe content +/// +/// # See Also +/// *[`tee`](https://man7.org/linux/man-pages/man2/tee.2.html) +#[cfg(linux_android)] pub fn tee( fd_in: RawFd, fd_out: RawFd, @@ -715,7 +976,11 @@ pub fn tee( Errno::result(ret).map(|r| r as usize) } -#[cfg(any(target_os = "linux", target_os = "android"))] +/// Splice user pages to/from a pipe +/// +/// # See Also +/// *[`vmsplice`](https://man7.org/linux/man-pages/man2/vmsplice.2.html) +#[cfg(linux_android)] pub fn vmsplice( fd: RawFd, iov: &[std::io::IoSlice<'_>], @@ -724,7 +989,7 @@ pub fn vmsplice( let ret = unsafe { libc::vmsplice( fd, - iov.as_ptr() as *const libc::iovec, + iov.as_ptr().cast(), iov.len(), flags.bits(), ) @@ -793,16 +1058,22 @@ pub struct SpacectlRange(pub libc::off_t, pub libc::off_t); #[cfg(any(target_os = "freebsd"))] impl SpacectlRange { + /// Is the range empty? + /// + /// After a successful call to [`fspacectl`], A value of `true` for `SpacectlRange::is_empty` + /// indicates that the operation is complete. #[inline] pub fn is_empty(&self) -> bool { self.1 == 0 } + /// Remaining length of the range #[inline] pub fn len(&self) -> libc::off_t { self.1 } + /// Next file offset to operate on #[inline] pub fn offset(&self) -> libc::off_t { self.0 @@ -849,6 +1120,7 @@ impl SpacectlRange { /// assert_eq!(buf, b"012\0\0\0\0\0\09abcdef"); /// ``` #[cfg(target_os = "freebsd")] +#[inline] // Delays codegen, preventing linker errors with dylibs and --no-allow-shlib-undefined pub fn fspacectl(fd: RawFd, range: SpacectlRange) -> Result<SpacectlRange> { let mut rqsr = libc::spacectl_range { r_offset: range.0, @@ -897,6 +1169,7 @@ pub fn fspacectl(fd: RawFd, range: SpacectlRange) -> Result<SpacectlRange> { /// assert_eq!(buf, b"012\0\0\0\0\0\09abcdef"); /// ``` #[cfg(target_os = "freebsd")] +#[inline] // Delays codegen, preventing linker errors with dylibs and --no-allow-shlib-undefined pub fn fspacectl_all( fd: RawFd, offset: libc::off_t, @@ -922,8 +1195,7 @@ pub fn fspacectl_all( } #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, target_os = "emscripten", target_os = "fuchsia", target_os = "wasi", @@ -937,21 +1209,34 @@ mod posix_fadvise { #[cfg(feature = "fs")] libc_enum! { + /// The specific advice provided to [`posix_fadvise`]. #[repr(i32)] #[non_exhaustive] #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] pub enum PosixFadviseAdvice { + /// Revert to the default data access behavior. POSIX_FADV_NORMAL, + /// The file data will be accessed sequentially. POSIX_FADV_SEQUENTIAL, + /// A hint that file data will be accessed randomly, and prefetching is likely not + /// advantageous. POSIX_FADV_RANDOM, + /// The specified data will only be accessed once and then not reused. POSIX_FADV_NOREUSE, + /// The specified data will be accessed in the near future. POSIX_FADV_WILLNEED, + /// The specified data will not be accessed in the near future. POSIX_FADV_DONTNEED, } } feature! { #![feature = "fs"] + /// Allows a process to describe to the system its data access behavior for an open file + /// descriptor. + /// + /// # See Also + /// * [`posix_fadvise`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_fadvise.html) pub fn posix_fadvise( fd: RawFd, offset: libc::off_t, @@ -963,20 +1248,22 @@ mod posix_fadvise { if res == 0 { Ok(()) } else { - Err(Errno::from_i32(res)) + Err(Errno::from_raw(res)) } } } } +/// Pre-allocate storage for a range in a file +/// +/// # See Also +/// * [`posix_fallocate`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_fallocate.html) #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "dragonfly", + linux_android, + freebsdlike, target_os = "emscripten", target_os = "fuchsia", target_os = "wasi", - target_os = "freebsd" ))] pub fn posix_fallocate( fd: RawFd, @@ -987,7 +1274,7 @@ pub fn posix_fallocate( match Errno::result(res) { Err(err) => Err(err), Ok(0) => Ok(()), - Ok(errno) => Err(Errno::from_i32(errno)), + Ok(errno) => Err(Errno::from_raw(errno)), } } } diff --git a/third_party/rust/nix/src/features.rs b/third_party/rust/nix/src/features.rs index 9e292cbf5d..0a0c618096 100644 --- a/third_party/rust/nix/src/features.rs +++ b/third_party/rust/nix/src/features.rs @@ -1,7 +1,7 @@ //! Feature tests for OS functionality pub use self::os::*; -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] mod os { use crate::sys::utsname::uname; use crate::Result; @@ -98,11 +98,10 @@ mod os { } #[cfg(any( - target_os = "dragonfly", // Since ??? - target_os = "freebsd", // Since 10.0 + freebsdlike, // FreeBSD since 10.0 DragonFlyBSD since ??? + netbsdlike, // NetBSD since 6.0 OpenBSD since 5.7 + target_os = "hurd", // Since glibc 2.28 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 { @@ -114,8 +113,7 @@ mod os { #[cfg(any( target_os = "aix", - target_os = "macos", - target_os = "ios", + apple_targets, target_os = "fuchsia", target_os = "haiku", target_os = "solaris" diff --git a/third_party/rust/nix/src/ifaddrs.rs b/third_party/rust/nix/src/ifaddrs.rs index 70b50b01eb..b3de64b01a 100644 --- a/third_party/rust/nix/src/ifaddrs.rs +++ b/third_party/rust/nix/src/ifaddrs.rs @@ -4,7 +4,7 @@ //! of interfaces and their associated addresses. use cfg_if::cfg_if; -#[cfg(any(target_os = "ios", target_os = "macos"))] +#[cfg(apple_targets)] use std::convert::TryFrom; use std::ffi; use std::iter::Iterator; @@ -33,7 +33,7 @@ pub struct InterfaceAddress { } cfg_if! { - if #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux"))] { + if #[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))] { fn get_ifu_from_sockaddr(info: &libc::ifaddrs) -> *const libc::sockaddr { info.ifa_ifu } @@ -53,7 +53,7 @@ cfg_if! { /// 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"))] +#[cfg(apple_targets)] unsafe fn workaround_xnu_bug(info: &libc::ifaddrs) -> Option<SockaddrStorage> { let src_sock = info.ifa_netmask; if src_sock.is_null() { @@ -62,22 +62,24 @@ unsafe fn workaround_xnu_bug(info: &libc::ifaddrs) -> Option<SockaddrStorage> { 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(), - ); + let dst_sock = unsafe { + // memcpy only sa_len bytes, assume the rest is zero + std::ptr::copy_nonoverlapping( + src_sock as *const u8, + dst_sock.as_mut_ptr().cast(), + (*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(); + // 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(); + 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) + unsafe { SockaddrStorage::from_raw(dst_sock_ptr, None) } } impl InterfaceAddress { @@ -85,14 +87,16 @@ impl InterfaceAddress { 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"))] + #[cfg(apple_targets)] let netmask = unsafe { workaround_xnu_bug(info) }; - #[cfg(not(any(target_os = "ios", target_os = "macos")))] + #[cfg(not(apple_targets))] 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), + flags: InterfaceFlags::from_bits_truncate( + info.ifa_flags as IflagsType, + ), address, netmask, broadcast: None, diff --git a/third_party/rust/nix/src/kmod.rs b/third_party/rust/nix/src/kmod.rs index d3725c3f8a..5cf2ed2c39 100644 --- a/third_party/rust/nix/src/kmod.rs +++ b/third_party/rust/nix/src/kmod.rs @@ -102,7 +102,11 @@ libc_bitflags!( /// 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 { + /// `delete_module` will return immediately, with an error, if the module has a nonzero + /// reference count. O_NONBLOCK; + /// `delete_module` will unload the module immediately, regardless of whether it has a + /// nonzero reference count. O_TRUNC; } ); diff --git a/third_party/rust/nix/src/lib.rs b/third_party/rust/nix/src/lib.rs index af0c67b0f3..dffac29b54 100644 --- a/third_party/rust/nix/src/lib.rs +++ b/third_party/rust/nix/src/lib.rs @@ -12,6 +12,7 @@ //! * `dir` - Stuff relating to directory iteration //! * `env` - Manipulate environment variables //! * `event` - Event-driven APIs, like `kqueue` and `epoll` +//! * `fanotify` - Linux's `fanotify` filesystem events monitoring API //! * `feature` - Query characteristics of the OS at runtime //! * `fs` - File system functionality //! * `hostname` - Get and set the system's hostname @@ -41,7 +42,6 @@ //! * `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"] @@ -54,6 +54,7 @@ feature = "dir", feature = "env", feature = "event", + feature = "fanotify", feature = "feature", feature = "fs", feature = "hostname", @@ -90,6 +91,7 @@ #![warn(missing_docs)] #![cfg_attr(docsrs, feature(doc_cfg))] #![deny(clippy::cast_ptr_alignment)] +#![deny(unsafe_op_in_unsafe_fn)] // Re-exported external crates pub use libc; @@ -116,42 +118,29 @@ 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"))] + #[cfg(any(linux_android, + bsd, + solarish))] #[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"))] +#[cfg(linux_android)] 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" -))] +#[cfg(any(freebsdlike, target_os = "linux", target_os = "netbsd"))] feature! { #![feature = "mqueue"] pub mod mqueue; @@ -173,7 +162,6 @@ feature! { pub mod sys; feature! { #![feature = "time"] - #[allow(missing_docs)] pub mod time; } // This can be implemented for other platforms as soon as libc @@ -192,9 +180,11 @@ feature! { #[allow(missing_docs)] pub mod ucontext; } -#[allow(missing_docs)] pub mod unistd; +#[cfg(any(feature = "poll", feature = "event"))] +mod poll_timeout; + use std::ffi::{CStr, CString, OsStr}; use std::mem::MaybeUninit; use std::os::unix::ffi::OsStrExt; @@ -311,7 +301,7 @@ impl NixPath for [u8] { } let mut buf = MaybeUninit::<[u8; MAX_STACK_ALLOCATION]>::uninit(); - let buf_ptr = buf.as_mut_ptr() as *mut u8; + let buf_ptr = buf.as_mut_ptr().cast(); unsafe { ptr::copy_nonoverlapping(self.as_ptr(), buf_ptr, self.len()); diff --git a/third_party/rust/nix/src/macros.rs b/third_party/rust/nix/src/macros.rs index adff2bc6be..3010a1a053 100644 --- a/third_party/rust/nix/src/macros.rs +++ b/third_party/rust/nix/src/macros.rs @@ -27,9 +27,9 @@ macro_rules! feature { /// /// PROT_WRITE enables write protect /// PROT_WRITE; /// PROT_EXEC; -/// #[cfg(any(target_os = "linux", target_os = "android"))] +/// #[cfg(linux_android)] /// PROT_GROWSDOWN; -/// #[cfg(any(target_os = "linux", target_os = "android"))] +/// #[cfg(linux_android)] /// PROT_GROWSUP; /// } /// } @@ -89,9 +89,9 @@ macro_rules! libc_bitflags { /// PROT_READ, /// PROT_WRITE, /// PROT_EXEC, -/// #[cfg(any(target_os = "linux", target_os = "android"))] +/// #[cfg(linux_android)] /// PROT_GROWSDOWN, -/// #[cfg(any(target_os = "linux", target_os = "android"))] +/// #[cfg(linux_android)] /// PROT_GROWSUP, /// } /// } diff --git a/third_party/rust/nix/src/mount/bsd.rs b/third_party/rust/nix/src/mount/bsd.rs index 6ed2dc7fbf..248e0ab1d2 100644 --- a/third_party/rust/nix/src/mount/bsd.rs +++ b/third_party/rust/nix/src/mount/bsd.rs @@ -17,36 +17,29 @@ libc_bitflags!( 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())))] + #[cfg(any(apple_targets, target_os = "freebsd"))] MNT_MULTILABEL; /// Disable read clustering. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] MNT_NOCLUSTERR; /// Disable write clustering. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] 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; @@ -55,8 +48,7 @@ libc_bitflags!( /// 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())))] + #[cfg(freebsdlike)] MNT_NOSYMFOLLOW; /// Mount read-only. MNT_RDONLY; @@ -66,39 +58,29 @@ libc_bitflags!( /// 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())))] + #[cfg(any(apple_targets, target_os = "freebsd"))] 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())))] + #[cfg(any(freebsdlike, netbsdlike))] 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())))] + #[cfg(freebsdlike)] MNT_SUIDDIR; /// All I/O to the file system should be done synchronously. MNT_SYNCHRONOUS; /// Union with underlying fs. #[cfg(any( - target_os = "macos", + apple_targets, 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; } ); @@ -198,7 +180,6 @@ pub type NmountResult = std::result::Result<(), NmountError>; /// * [`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 @@ -210,12 +191,11 @@ pub struct Nmount<'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_base: val.as_ptr().cast_mut().cast(), iov_len: val.len(), }); self.is_owned.push(is_owned); @@ -386,7 +366,7 @@ impl<'a> Nmount<'a> { // 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_base: errmsg.as_mut_ptr().cast(), iov_len: errmsg.len(), }); @@ -396,13 +376,10 @@ impl<'a> Nmount<'a> { 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()) - } + let errmsg = if errmsg[0] == 0 { + None + } else { + CStr::from_bytes_until_nul(&errmsg[..]).ok() }; Err(NmountError::new(error, errmsg)) } diff --git a/third_party/rust/nix/src/mount/linux.rs b/third_party/rust/nix/src/mount/linux.rs index e987603786..aa166bc9d3 100644 --- a/third_party/rust/nix/src/mount/linux.rs +++ b/third_party/rust/nix/src/mount/linux.rs @@ -85,7 +85,7 @@ libc_bitflags!( MNT_DETACH; /// Mark the mount point as expired. MNT_EXPIRE; - /// Don't dereference `target` if it is a symlink. + /// Don't dereference `target` if it is a symlink. UMOUNT_NOFOLLOW; } ); diff --git a/third_party/rust/nix/src/mount/mod.rs b/third_party/rust/nix/src/mount/mod.rs index e98b49c343..8caf27f7df 100644 --- a/third_party/rust/nix/src/mount/mod.rs +++ b/third_party/rust/nix/src/mount/mod.rs @@ -1,26 +1,12 @@ //! Mount file systems -#[cfg(any(target_os = "android", target_os = "linux"))] -#[cfg_attr(docsrs, doc(cfg(all())))] +#[cfg(linux_android)] mod linux; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] 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())))] +#[cfg(bsd)] mod bsd; -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" -))] +#[cfg(bsd)] pub use self::bsd::*; diff --git a/third_party/rust/nix/src/mqueue.rs b/third_party/rust/nix/src/mqueue.rs index fb07d2accb..7f9d687521 100644 --- a/third_party/rust/nix/src/mqueue.rs +++ b/third_party/rust/nix/src/mqueue.rs @@ -35,7 +35,7 @@ use crate::NixPath; use crate::Result; use crate::sys::stat::Mode; -use libc::{self, c_char, mqd_t, size_t}; +use libc::{self, mqd_t, size_t}; use std::mem; #[cfg(any( target_os = "linux", @@ -88,11 +88,9 @@ pub struct MqdT(mqd_t); // 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 { @@ -205,7 +203,7 @@ pub fn mq_receive( let res = unsafe { libc::mq_receive( mqdes.0, - message.as_mut_ptr() as *mut c_char, + message.as_mut_ptr().cast(), len, msg_prio as *mut u32, ) @@ -229,7 +227,7 @@ feature! { let res = unsafe { libc::mq_timedreceive( mqdes.0, - message.as_mut_ptr() as *mut c_char, + message.as_mut_ptr().cast(), len, msg_prio as *mut u32, abstime.as_ref(), @@ -244,12 +242,7 @@ feature! { /// 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, - ) + libc::mq_send(mqdes.0, message.as_ptr().cast(), message.len(), msq_prio) }; Errno::result(res).map(drop) } diff --git a/third_party/rust/nix/src/net/if_.rs b/third_party/rust/nix/src/net/if_.rs index ec46260714..c66b5dc0b3 100644 --- a/third_party/rust/nix/src/net/if_.rs +++ b/third_party/rust/nix/src/net/if_.rs @@ -3,9 +3,17 @@ //! Uses Linux and/or POSIX functions to resolve interface names like "eth0" //! or "socan1" into device numbers. +use std::fmt; use crate::{Error, NixPath, Result}; use libc::c_uint; +#[cfg(not(solarish))] +/// type alias for InterfaceFlags +pub type IflagsType = libc::c_int; +#[cfg(solarish)] +/// type alias for InterfaceFlags +pub type IflagsType = libc::c_longlong; + /// Resolve an interface into a interface number. pub fn if_nametoindex<P: ?Sized + NixPath>(name: &P) -> Result<c_uint> { let if_index = name @@ -20,323 +28,236 @@ pub fn if_nametoindex<P: ?Sized + NixPath>(name: &P) -> Result<c_uint> { libc_bitflags!( /// Standard interface flags, used by `getifaddrs` - pub struct InterfaceFlags: libc::c_int { + pub struct InterfaceFlags: IflagsType { + /// Interface is running. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - IFF_UP; + IFF_UP as IflagsType; /// Valid broadcast address set. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - IFF_BROADCAST; + IFF_BROADCAST as IflagsType; /// Internal debugging flag. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) #[cfg(not(target_os = "haiku"))] - IFF_DEBUG; + IFF_DEBUG as IflagsType; /// Interface is a loopback interface. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - IFF_LOOPBACK; + IFF_LOOPBACK as IflagsType; /// Interface is a point-to-point link. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - IFF_POINTOPOINT; + IFF_POINTOPOINT as IflagsType; /// Avoid use of trailers. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - #[cfg(any(target_os = "android", + #[cfg(any( + linux_android, + solarish, + apple_targets, 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; + target_os = "netbsd"))] + IFF_NOTRAILERS as IflagsType; /// Interface manages own routes. #[cfg(any(target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_SMART; + IFF_SMART as IflagsType; /// 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; + #[cfg(any( + linux_android, + bsd, + solarish, + target_os = "fuchsia"))] + IFF_RUNNING as IflagsType; /// No arp protocol, L2 destination address not set. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - IFF_NOARP; + IFF_NOARP as IflagsType; /// Interface is in promiscuous mode. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - IFF_PROMISC; + IFF_PROMISC as IflagsType; /// Receive all multicast packets. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - IFF_ALLMULTI; + IFF_ALLMULTI as IflagsType; /// 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())))] + #[cfg(any(linux_android, target_os = "fuchsia"))] 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())))] + #[cfg(any(target_os = "freebsd", apple_targets, netbsdlike))] IFF_OACTIVE; /// Protocol code on board. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_INTELLIGENT; + #[cfg(solarish)] + IFF_INTELLIGENT as IflagsType; /// 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())))] + #[cfg(any(linux_android, target_os = "fuchsia"))] 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())))] + #[cfg(bsd)] IFF_SIMPLEX; /// Supports multicast. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) - IFF_MULTICAST; + IFF_MULTICAST as IflagsType; /// 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())))] + #[cfg(bsd)] IFF_LINK0; /// Multicast using broadcast. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_MULTI_BCAST; + #[cfg(solarish)] + IFF_MULTI_BCAST as IflagsType; /// 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())))] + #[cfg(any(linux_android, target_os = "fuchsia"))] 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())))] + #[cfg(bsd)] IFF_LINK1; /// Non-unique address. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_UNNUMBERED; + #[cfg(solarish)] + IFF_UNNUMBERED as IflagsType; /// 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())))] + #[cfg(any(linux_android, target_os = "fuchsia"))] 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())))] + #[cfg(bsd)] 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())))] + #[cfg(any(freebsdlike, apple_targets))] IFF_ALTPHYS; /// DHCP controls interface. - #[cfg(any(target_os = "solaris", target_os = "illumos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_DHCPRUNNING; + #[cfg(solarish)] + IFF_DHCPRUNNING as IflagsType; /// 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())))] + #[cfg(any(linux_android, target_os = "fuchsia"))] IFF_DYNAMIC; /// Do not advertise. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_PRIVATE; + #[cfg(solarish)] + IFF_PRIVATE as IflagsType; /// 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; + #[cfg(solarish)] + IFF_NOXMIT as IflagsType; /// 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())))] + #[cfg(freebsdlike)] IFF_PPROMISC; /// Just on-link subnet. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_NOLOCAL; + #[cfg(solarish)] + IFF_NOLOCAL as IflagsType; /// 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())))] + #[cfg(freebsdlike)] IFF_MONITOR; /// Address is deprecated. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_DEPRECATED; + #[cfg(solarish)] + IFF_DEPRECATED as IflagsType; /// Static ARP. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] IFF_STATICARP; /// Address from stateless addrconf. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_ADDRCONF; + #[cfg(solarish)] + IFF_ADDRCONF as IflagsType; /// 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; + #[cfg(solarish)] + IFF_ROUTER as IflagsType; /// 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; + #[cfg(solarish)] + IFF_NONUD as IflagsType; /// 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; + #[cfg(solarish)] + IFF_ANYCAST as IflagsType; /// Don't exchange routing info. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_NORTEXCH; + #[cfg(solarish)] + IFF_NORTEXCH as IflagsType; /// 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; + #[cfg(any(linux_android, target_os = "fuchsia"))] + IFF_NO_PI as IflagsType; /// 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; + #[cfg(any(linux_android, target_os = "fuchsia"))] + IFF_TUN as IflagsType; /// 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; + #[cfg(any(linux_android, target_os = "fuchsia"))] + IFF_TAP as IflagsType; /// IPv4 interface. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_IPV4; + #[cfg(solarish)] + IFF_IPV4 as IflagsType; /// IPv6 interface. - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_IPV6; + #[cfg(solarish)] + IFF_IPV6 as IflagsType; /// in.mpathd test address - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_NOFAILOVER; + #[cfg(solarish)] + IFF_NOFAILOVER as IflagsType; /// Interface has failed - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_FAILED; + #[cfg(solarish)] + IFF_FAILED as IflagsType; /// Interface is a hot-spare - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_STANDBY; + #[cfg(solarish)] + IFF_STANDBY as IflagsType; /// Functioning but not used - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_INACTIVE; + #[cfg(solarish)] + IFF_INACTIVE as IflagsType; /// 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; + #[cfg(solarish)] + IFF_OFFLINE as IflagsType; + /// Has CoS marking supported + #[cfg(solarish)] + IFF_COS_ENABLED as IflagsType; + /// Prefer as source addr + #[cfg(solarish)] + IFF_PREFERRED as IflagsType; /// 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; + #[cfg(solarish)] + IFF_TEMPORARY as IflagsType; + /// MTU set + #[cfg(solarish)] + IFF_FIXEDMTU as IflagsType; + /// Cannot send/receive packets + #[cfg(solarish)] + IFF_VIRTUAL as IflagsType; /// Local address in use - #[cfg(target_os = "solaris")] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_DUPLICATE; + #[cfg(solarish)] + IFF_DUPLICATE as IflagsType; /// IPMP IP interface - #[cfg(target_os = "solaris")] - #[cfg_attr(docsrs, doc(cfg(all())))] - IFF_IPMP; + #[cfg(solarish)] + IFF_IPMP as IflagsType; } ); +impl fmt::Display for InterfaceFlags { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + bitflags::parser::to_writer(self, f) + } +} + + #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", + bsd, target_os = "fuchsia", - target_os = "ios", target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "illumos", + solarish, ))] -#[cfg_attr(docsrs, doc(cfg(all())))] mod if_nameindex { use super::*; @@ -373,6 +294,7 @@ mod if_nameindex { } /// A list of the network interfaces available on this system. Obtained from [`if_nameindex()`]. + #[repr(transparent)] pub struct Interfaces { ptr: NonNull<libc::if_nameindex>, } @@ -388,7 +310,7 @@ mod if_nameindex { /// 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 ifs = self.ptr.as_ptr().cast(); let len = self.iter().count(); unsafe { std::slice::from_raw_parts(ifs, len) } } @@ -458,14 +380,9 @@ mod if_nameindex { } } #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", + bsd, target_os = "fuchsia", - target_os = "ios", target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "illumos", + solarish, ))] pub use if_nameindex::*; diff --git a/third_party/rust/nix/src/poll.rs b/third_party/rust/nix/src/poll.rs index 9181bf7f30..0ad9f40d3b 100644 --- a/third_party/rust/nix/src/poll.rs +++ b/third_party/rust/nix/src/poll.rs @@ -2,6 +2,7 @@ use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd}; use crate::errno::Errno; +pub use crate::poll_timeout::PollTimeout; use crate::Result; /// This is a wrapper around `libc::pollfd`. @@ -22,24 +23,35 @@ pub struct PollFd<'fd> { impl<'fd> PollFd<'fd> { /// Creates a new `PollFd` specifying the events of interest /// for a given file descriptor. - // - // Different from other I/O-safe interfaces, here, we have to take `AsFd` - // by reference to prevent the case where the `fd` is closed but it is - // still in use. For example: + /// + /// # Examples + /// ```no_run + /// # use std::os::unix::io::{AsFd, AsRawFd, FromRawFd}; + /// # use nix::{ + /// # poll::{PollTimeout, PollFd, PollFlags, poll}, + /// # unistd::{pipe, read} + /// # }; + /// let (r, w) = pipe().unwrap(); + /// let pfd = PollFd::new(r.as_fd(), PollFlags::POLLIN); + /// let mut fds = [pfd]; + /// poll(&mut fds, PollTimeout::NONE).unwrap(); + /// let mut buf = [0u8; 80]; + /// read(r.as_raw_fd(), &mut buf[..]); + /// ``` + // Unlike I/O functions, constructors like this must take `BorrowedFd` + // instead of AsFd or &AsFd. Otherwise, an `OwnedFd` argument would be + // dropped at the end of the method, leaving the structure referencing a + // closed file descriptor. For example: // // ```rust - // let (reader, _) = pipe().unwrap(); - // - // // If `PollFd::new()` takes `AsFd` by value, then `reader` will be consumed, - // // but the file descriptor of `reader` will still be in use. - // let pollfd = PollFd::new(reader, flag); - // + // let (r, _) = pipe().unwrap(); + // let pollfd = PollFd::new(r, flag); // Drops the OwnedFd // // Do something with `pollfd`, which uses the CLOSED fd. // ``` - pub fn new<Fd: AsFd>(fd: &'fd Fd, events: PollFlags) -> PollFd<'fd> { + pub fn new(fd: BorrowedFd<'fd>, events: PollFlags) -> PollFd<'fd> { PollFd { pollfd: libc::pollfd { - fd: fd.as_fd().as_raw_fd(), + fd: fd.as_raw_fd(), events: events.bits(), revents: PollFlags::empty().bits(), }, @@ -133,19 +145,15 @@ libc_bitflags! { 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); @@ -184,16 +192,19 @@ libc_bitflags! { /// /// 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> { +/// interval may overrun by a small amount. Specifying a [`PollTimeout::NONE`] +/// in timeout means an infinite timeout. Specifying a timeout of +/// [`PollTimeout::ZERO`] causes `poll()` to return immediately, even if no file +/// descriptors are ready. +pub fn poll<T: Into<PollTimeout>>( + fds: &mut [PollFd], + timeout: T, +) -> Result<libc::c_int> { let res = unsafe { libc::poll( - fds.as_mut_ptr() as *mut libc::pollfd, + fds.as_mut_ptr().cast(), fds.len() as libc::nfds_t, - timeout, + i32::from(timeout.into()), ) }; @@ -213,7 +224,7 @@ feature! { /// 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"))] +#[cfg(any(linux_android, freebsdlike))] pub fn ppoll( fds: &mut [PollFd], timeout: Option<crate::sys::time::TimeSpec>, @@ -223,7 +234,7 @@ pub fn ppoll( 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, + libc::ppoll(fds.as_mut_ptr().cast(), fds.len() as libc::nfds_t, timeout, sigmask) diff --git a/third_party/rust/nix/src/poll_timeout.rs b/third_party/rust/nix/src/poll_timeout.rs new file mode 100644 index 0000000000..f7d9015f56 --- /dev/null +++ b/third_party/rust/nix/src/poll_timeout.rs @@ -0,0 +1,224 @@ +use std::time::Duration; + +/// PollTimeout argument for polling. +#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)] +pub struct PollTimeout(i32); + +impl PollTimeout { + /// Blocks indefinitely. + /// + /// > Specifying a negative value in timeout means an infinite timeout. + pub const NONE: Self = Self(-1); + /// Returns immediately. + /// + /// > Specifying a timeout of zero causes poll() to return immediately, even if no file + /// > descriptors are ready. + pub const ZERO: Self = Self(0); + /// Blocks for at most [`i32::MAX`] milliseconds. + pub const MAX: Self = Self(i32::MAX); + /// Returns if `self` equals [`PollTimeout::NONE`]. + pub fn is_none(&self) -> bool { + // > Specifying a negative value in timeout means an infinite timeout. + *self <= Self::NONE + } + /// Returns if `self` does not equal [`PollTimeout::NONE`]. + pub fn is_some(&self) -> bool { + !self.is_none() + } + /// Returns the timeout in milliseconds if there is some, otherwise returns `None`. + pub fn as_millis(&self) -> Option<u32> { + self.is_some().then_some(u32::try_from(self.0).unwrap()) + } + /// Returns the timeout as a `Duration` if there is some, otherwise returns `None`. + pub fn duration(&self) -> Option<Duration> { + self.as_millis() + .map(|x| Duration::from_millis(u64::from(x))) + } +} + +/// Error type for integer conversions into `PollTimeout`. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PollTimeoutTryFromError { + /// Passing a value less than -1 is invalid on some systems, see + /// <https://man.freebsd.org/cgi/man.cgi?poll#end>. + TooNegative, + /// Passing a value greater than `i32::MAX` is invalid. + TooPositive, +} + +impl std::fmt::Display for PollTimeoutTryFromError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::TooNegative => write!(f, "Passed a negative timeout less than -1."), + Self::TooPositive => write!(f, "Passed a positive timeout greater than `i32::MAX` milliseconds.") + } + } +} + +impl std::error::Error for PollTimeoutTryFromError {} + +impl<T: Into<PollTimeout>> From<Option<T>> for PollTimeout { + fn from(x: Option<T>) -> Self { + x.map_or(Self::NONE, |x| x.into()) + } +} +impl TryFrom<Duration> for PollTimeout { + type Error = PollTimeoutTryFromError; + fn try_from(x: Duration) -> std::result::Result<Self, Self::Error> { + Ok(Self( + i32::try_from(x.as_millis()) + .map_err(|_| PollTimeoutTryFromError::TooPositive)?, + )) + } +} +impl TryFrom<u128> for PollTimeout { + type Error = PollTimeoutTryFromError; + fn try_from(x: u128) -> std::result::Result<Self, Self::Error> { + Ok(Self( + i32::try_from(x) + .map_err(|_| PollTimeoutTryFromError::TooPositive)?, + )) + } +} +impl TryFrom<u64> for PollTimeout { + type Error = PollTimeoutTryFromError; + fn try_from(x: u64) -> std::result::Result<Self, Self::Error> { + Ok(Self( + i32::try_from(x) + .map_err(|_| PollTimeoutTryFromError::TooPositive)?, + )) + } +} +impl TryFrom<u32> for PollTimeout { + type Error = PollTimeoutTryFromError; + fn try_from(x: u32) -> std::result::Result<Self, Self::Error> { + Ok(Self( + i32::try_from(x) + .map_err(|_| PollTimeoutTryFromError::TooPositive)?, + )) + } +} +impl From<u16> for PollTimeout { + fn from(x: u16) -> Self { + Self(i32::from(x)) + } +} +impl From<u8> for PollTimeout { + fn from(x: u8) -> Self { + Self(i32::from(x)) + } +} +impl TryFrom<i128> for PollTimeout { + type Error = PollTimeoutTryFromError; + fn try_from(x: i128) -> std::result::Result<Self, Self::Error> { + match x { + ..=-2 => Err(PollTimeoutTryFromError::TooNegative), + -1.. => Ok(Self( + i32::try_from(x) + .map_err(|_| PollTimeoutTryFromError::TooPositive)?, + )), + } + } +} +impl TryFrom<i64> for PollTimeout { + type Error = PollTimeoutTryFromError; + fn try_from(x: i64) -> std::result::Result<Self, Self::Error> { + match x { + ..=-2 => Err(PollTimeoutTryFromError::TooNegative), + -1.. => Ok(Self( + i32::try_from(x) + .map_err(|_| PollTimeoutTryFromError::TooPositive)?, + )), + } + } +} +impl TryFrom<i32> for PollTimeout { + type Error = PollTimeoutTryFromError; + fn try_from(x: i32) -> std::result::Result<Self, Self::Error> { + match x { + ..=-2 => Err(PollTimeoutTryFromError::TooNegative), + -1.. => Ok(Self(x)), + } + } +} +impl TryFrom<i16> for PollTimeout { + type Error = PollTimeoutTryFromError; + fn try_from(x: i16) -> std::result::Result<Self, Self::Error> { + match x { + ..=-2 => Err(PollTimeoutTryFromError::TooNegative), + -1.. => Ok(Self(i32::from(x))), + } + } +} +impl TryFrom<i8> for PollTimeout { + type Error = PollTimeoutTryFromError; + fn try_from(x: i8) -> std::result::Result<Self, Self::Error> { + match x { + ..=-2 => Err(PollTimeoutTryFromError::TooNegative), + -1.. => Ok(Self(i32::from(x))), + } + } +} +impl TryFrom<PollTimeout> for Duration { + type Error = (); + fn try_from(x: PollTimeout) -> std::result::Result<Self, ()> { + x.duration().ok_or(()) + } +} +impl TryFrom<PollTimeout> for u128 { + type Error = <Self as TryFrom<i32>>::Error; + fn try_from(x: PollTimeout) -> std::result::Result<Self, Self::Error> { + Self::try_from(x.0) + } +} +impl TryFrom<PollTimeout> for u64 { + type Error = <Self as TryFrom<i32>>::Error; + fn try_from(x: PollTimeout) -> std::result::Result<Self, Self::Error> { + Self::try_from(x.0) + } +} +impl TryFrom<PollTimeout> for u32 { + type Error = <Self as TryFrom<i32>>::Error; + fn try_from(x: PollTimeout) -> std::result::Result<Self, Self::Error> { + Self::try_from(x.0) + } +} +impl TryFrom<PollTimeout> for u16 { + type Error = <Self as TryFrom<i32>>::Error; + fn try_from(x: PollTimeout) -> std::result::Result<Self, Self::Error> { + Self::try_from(x.0) + } +} +impl TryFrom<PollTimeout> for u8 { + type Error = <Self as TryFrom<i32>>::Error; + fn try_from(x: PollTimeout) -> std::result::Result<Self, Self::Error> { + Self::try_from(x.0) + } +} +impl From<PollTimeout> for i128 { + fn from(x: PollTimeout) -> Self { + Self::from(x.0) + } +} +impl From<PollTimeout> for i64 { + fn from(x: PollTimeout) -> Self { + Self::from(x.0) + } +} +impl From<PollTimeout> for i32 { + fn from(x: PollTimeout) -> Self { + x.0 + } +} +impl TryFrom<PollTimeout> for i16 { + type Error = <Self as TryFrom<i32>>::Error; + fn try_from(x: PollTimeout) -> std::result::Result<Self, Self::Error> { + Self::try_from(x.0) + } +} +impl TryFrom<PollTimeout> for i8 { + type Error = <Self as TryFrom<i32>>::Error; + fn try_from(x: PollTimeout) -> std::result::Result<Self, Self::Error> { + Self::try_from(x.0) + } +} diff --git a/third_party/rust/nix/src/pty.rs b/third_party/rust/nix/src/pty.rs index 455828b703..74f8ecf0df 100644 --- a/third_party/rust/nix/src/pty.rs +++ b/third_party/rust/nix/src/pty.rs @@ -71,7 +71,7 @@ impl io::Read for PtyMaster { impl io::Write for PtyMaster { fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - unistd::write(self.0.as_raw_fd(), buf).map_err(io::Error::from) + unistd::write(&self.0, buf).map_err(io::Error::from) } fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -86,7 +86,7 @@ impl io::Read for &PtyMaster { impl io::Write for &PtyMaster { fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - unistd::write(self.0.as_raw_fd(), buf).map_err(io::Error::from) + unistd::write(&self.0, buf).map_err(io::Error::from) } fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -169,12 +169,12 @@ pub fn posix_openpt(flags: fcntl::OFlag) -> Result<PtyMaster> { /// 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()); + let name_ptr = unsafe { libc::ptsname(fd.as_raw_fd()) }; if name_ptr.is_null() { return Err(Errno::last()); } - let name = CStr::from_ptr(name_ptr); + let name = unsafe { CStr::from_ptr(name_ptr) }; Ok(name.to_string_lossy().into_owned()) } @@ -187,8 +187,7 @@ pub unsafe fn ptsname(fd: &PtyMaster) -> Result<String> { /// /// 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())))] +#[cfg(linux_android)] #[inline] pub fn ptsname_r(fd: &PtyMaster) -> Result<String> { let mut name_buf = Vec::<libc::c_char>::with_capacity(64); @@ -342,7 +341,7 @@ pub unsafe fn forkpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b T .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 res = unsafe { libc::forkpty(master.as_mut_ptr(), ptr::null_mut(), term, win) }; let fork_result = Errno::result(res).map(|res| match res { 0 => ForkResult::Child, @@ -350,7 +349,7 @@ pub unsafe fn forkpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b T })?; Ok(ForkptyResult { - master: OwnedFd::from_raw_fd(master.assume_init()), + master: unsafe { OwnedFd::from_raw_fd( master.assume_init() ) }, fork_result, }) } diff --git a/third_party/rust/nix/src/sched.rs b/third_party/rust/nix/src/sched.rs index c9d5d6d8a1..d76d5581d1 100644 --- a/third_party/rust/nix/src/sched.rs +++ b/third_party/rust/nix/src/sched.rs @@ -4,11 +4,10 @@ //! [sched.h](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sched.h.html) use crate::{Errno, Result}; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] pub use self::sched_linux_like::*; -#[cfg(any(target_os = "android", target_os = "linux"))] -#[cfg_attr(docsrs, doc(cfg(all())))] +#[cfg(linux_android)] mod sched_linux_like { use crate::errno::Errno; use crate::unistd::Pid; @@ -117,17 +116,19 @@ mod sched_linux_like { } 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); - let res = 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, - ); + let res = unsafe { + 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) } @@ -151,20 +152,10 @@ mod sched_linux_like { } } -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux" -))] +#[cfg(any(linux_android, freebsdlike))] pub use self::sched_affinity::*; -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux" -))] +#[cfg(any(linux_android, freebsdlike))] mod sched_affinity { use crate::errno::Errno; use crate::unistd::Pid; diff --git a/third_party/rust/nix/src/sys/aio.rs b/third_party/rust/nix/src/sys/aio.rs index 5471177e3e..e9213c6434 100644 --- a/third_party/rust/nix/src/sys/aio.rs +++ b/third_party/rust/nix/src/sys/aio.rs @@ -35,7 +35,7 @@ use std::{ ptr, thread, }; -use libc::{c_void, off_t}; +use libc::off_t; use pin_utils::unsafe_pinned; use crate::{ @@ -53,12 +53,9 @@ libc_enum! { /// do it like `fsync` O_SYNC, /// on supported operating systems only, do it like `fdatasync` - #[cfg(any(target_os = "ios", + #[cfg(any(apple_targets, target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + netbsdlike))] O_DSYNC } impl TryFrom<i32> @@ -161,7 +158,7 @@ impl AioCb { let r = unsafe { libc::aio_error(&self.aiocb().0) }; match r { 0 => Ok(()), - num if num > 0 => Err(Errno::from_i32(num)), + num if num > 0 => Err(Errno::from_raw(num)), -1 => Err(Errno::last()), num => panic!("unknown aio_error return value {num:?}"), } @@ -581,7 +578,7 @@ impl<'a> AioRead<'a> { ) -> 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_buf = buf.as_mut_ptr().cast(); aiocb.aiocb.0.aio_lio_opcode = libc::LIO_READ; aiocb.aiocb.0.aio_offset = offs; AioRead { @@ -702,7 +699,7 @@ impl<'a> AioReadv<'a> { // 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_buf = bufs.as_mut_ptr().cast(); aiocb.aiocb.0.aio_lio_opcode = libc::LIO_READV; aiocb.aiocb.0.aio_offset = offs; AioReadv { @@ -817,7 +814,7 @@ impl<'a> AioWrite<'a> { // 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_buf = buf.as_ptr().cast_mut().cast(); aiocb.aiocb.0.aio_lio_opcode = libc::LIO_WRITE; aiocb.aiocb.0.aio_offset = offs; AioWrite { @@ -935,7 +932,7 @@ impl<'a> AioWritev<'a> { // 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_buf = bufs.as_ptr().cast_mut().cast(); aiocb.aiocb.0.aio_lio_opcode = libc::LIO_WRITEV; aiocb.aiocb.0.aio_offset = offs; AioWritev { @@ -1055,7 +1052,8 @@ pub fn aio_suspend( // generic, and accepting arguments like &[AioWrite]. But that would // prevent using aio_suspend to wait on a heterogeneous list of mixed // operations. - let v = list.iter() + let v = list + .iter() .map(|x| x.as_ref() as *const libc::aiocb) .collect::<Vec<*const libc::aiocb>>(); let p = v.as_ptr(); @@ -1175,7 +1173,10 @@ pub fn aio_suspend( /// // notification, we know that all operations are complete. /// assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len()); /// ``` -#[deprecated(since = "0.27.0", note = "https://github.com/nix-rust/nix/issues/2017")] +#[deprecated( + since = "0.27.0", + note = "https://github.com/nix-rust/nix/issues/2017" +)] pub fn lio_listio( mode: LioMode, list: &mut [Pin<&mut dyn AsMut<libc::aiocb>>], @@ -1190,56 +1191,3 @@ pub fn lio_listio( }) .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/third_party/rust/nix/src/sys/epoll.rs b/third_party/rust/nix/src/sys/epoll.rs index 36f9c17d0e..ec146a8c53 100644 --- a/third_party/rust/nix/src/sys/epoll.rs +++ b/third_party/rust/nix/src/sys/epoll.rs @@ -1,4 +1,5 @@ use crate::errno::Errno; +pub use crate::poll_timeout::PollTimeout as EpollTimeout; use crate::Result; use libc::{self, c_int}; use std::mem; @@ -71,32 +72,32 @@ impl EpollEvent { /// A safe wrapper around [`epoll`](https://man7.org/linux/man-pages/man7/epoll.7.html). /// ``` -/// # use nix::sys::{epoll::{Epoll, EpollEvent, EpollFlags, EpollCreateFlags}, eventfd::{eventfd, EfdFlags}}; +/// # use nix::sys::{epoll::{EpollTimeout, Epoll, EpollEvent, EpollFlags, EpollCreateFlags}, eventfd::{EventFd, EfdFlags}}; /// # use nix::unistd::write; -/// # use std::os::unix::io::{OwnedFd, FromRawFd, AsRawFd, AsFd}; +/// # use std::os::unix::io::{OwnedFd, FromRawFd, AsFd}; /// # use std::time::{Instant, Duration}; /// # fn main() -> nix::Result<()> { /// const DATA: u64 = 17; -/// const MILLIS: u64 = 100; +/// const MILLIS: u8 = 100; /// /// // Create epoll /// let epoll = Epoll::new(EpollCreateFlags::empty())?; /// /// // Create eventfd & Add event -/// let eventfd = eventfd(0, EfdFlags::empty())?; +/// let eventfd = EventFd::new()?; /// epoll.add(&eventfd, EpollEvent::new(EpollFlags::EPOLLIN,DATA))?; /// /// // Arm eventfd & Time wait -/// write(eventfd.as_raw_fd(), &1u64.to_ne_bytes())?; +/// eventfd.arm()?; /// let now = Instant::now(); /// /// // Wait on event /// let mut events = [EpollEvent::empty()]; -/// epoll.wait(&mut events, MILLIS as isize)?; +/// epoll.wait(&mut events, MILLIS)?; /// /// // Assert data correct & timeout didn't occur /// assert_eq!(events[0].data(), DATA); -/// assert!(now.elapsed() < Duration::from_millis(MILLIS)); +/// assert!(now.elapsed().as_millis() < MILLIS.into()); /// # Ok(()) /// # } /// ``` @@ -140,17 +141,17 @@ impl Epoll { /// (This can be thought of as fetching items from the ready list of the epoll instance.) /// /// [`epoll_wait`](https://man7.org/linux/man-pages/man2/epoll_wait.2.html) - pub fn wait( + pub fn wait<T: Into<EpollTimeout>>( &self, events: &mut [EpollEvent], - timeout: isize, + timeout: T, ) -> Result<usize> { let res = unsafe { libc::epoll_wait( self.0.as_raw_fd(), - events.as_mut_ptr() as *mut libc::epoll_event, + events.as_mut_ptr().cast(), events.len() as c_int, - timeout as c_int, + timeout.into().into(), ) }; @@ -240,7 +241,7 @@ pub fn epoll_wait( let res = unsafe { libc::epoll_wait( epfd, - events.as_mut_ptr() as *mut libc::epoll_event, + events.as_mut_ptr().cast(), events.len() as c_int, timeout_ms as c_int, ) diff --git a/third_party/rust/nix/src/sys/event.rs b/third_party/rust/nix/src/sys/event.rs index ec7f7e277a..b294d27c70 100644 --- a/third_party/rust/nix/src/sys/event.rs +++ b/third_party/rust/nix/src/sys/event.rs @@ -10,6 +10,7 @@ use libc::{c_int, c_long, intptr_t, time_t, timespec, uintptr_t}; use libc::{c_long, intptr_t, size_t, time_t, timespec, uintptr_t}; use std::convert::TryInto; use std::mem; +use std::os::fd::{AsFd, BorrowedFd}; use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd}; use std::ptr; @@ -29,6 +30,18 @@ pub struct KEvent { #[derive(Debug)] pub struct Kqueue(OwnedFd); +impl AsFd for Kqueue { + fn as_fd(&self) -> BorrowedFd<'_> { + self.0.as_fd() + } +} + +impl From<Kqueue> for OwnedFd { + fn from(value: Kqueue) -> Self { + value.0 + } +} + impl Kqueue { /// Create a new kernel event queue. pub fn new() -> Result<Self> { @@ -63,9 +76,9 @@ impl Kqueue { let res = unsafe { libc::kevent( self.0.as_raw_fd(), - changelist.as_ptr() as *const libc::kevent, + changelist.as_ptr().cast(), changelist.len() as type_of_nchanges, - eventlist.as_mut_ptr() as *mut libc::kevent, + eventlist.as_mut_ptr().cast(), eventlist.len() as type_of_nchanges, if let Some(ref timeout) = timeout_opt { timeout as *const timespec @@ -78,13 +91,7 @@ impl Kqueue { } } -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "openbsd" -))] +#[cfg(any(freebsdlike, apple_targets, target_os = "openbsd"))] type type_of_udata = *mut libc::c_void; #[cfg(target_os = "netbsd")] type type_of_udata = intptr_t; @@ -109,10 +116,7 @@ libc_enum! { /// Takes a descriptor as the identifier, and returns whenever one of /// the specified exceptional conditions has occurred on the descriptor. EVFILT_EXCEPT, - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos"))] + #[cfg(any(freebsdlike, apple_targets))] /// Establishes a file system monitor. EVFILT_FS, #[cfg(target_os = "freebsd")] @@ -120,7 +124,7 @@ libc_enum! { /// # See Also /// [lio_listio(2)](https://www.freebsd.org/cgi/man.cgi?query=lio_listio) EVFILT_LIO, - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(apple_targets)] /// Mach portsets EVFILT_MACHPORT, /// Notifies when a process performs one or more of the requested @@ -144,13 +148,10 @@ libc_enum! { EVFILT_SIGNAL, /// Establishes a timer and notifies when the timer expires. EVFILT_TIMER, - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos"))] + #[cfg(any(freebsdlike, apple_targets))] /// Notifies only when explicitly requested by the user. EVFILT_USER, - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(apple_targets)] /// Virtual memory events EVFILT_VM, /// Notifies when a requested event happens on a specified file. @@ -162,13 +163,7 @@ libc_enum! { impl TryFrom<type_of_event_filter> } -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "openbsd" -))] +#[cfg(any(freebsdlike, apple_targets, target_os = "openbsd"))] #[doc(hidden)] pub type type_of_event_flag = u16; #[cfg(target_os = "netbsd")] @@ -187,9 +182,7 @@ libc_bitflags! { EV_DELETE; #[allow(missing_docs)] EV_DISABLE; - #[cfg(any(target_os = "dragonfly", target_os = "freebsd", - target_os = "ios", target_os = "macos", - target_os = "netbsd", target_os = "openbsd"))] + #[cfg(bsd)] #[allow(missing_docs)] EV_DISPATCH; #[cfg(target_os = "freebsd")] @@ -201,7 +194,7 @@ libc_bitflags! { EV_EOF; #[allow(missing_docs)] EV_ERROR; - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] #[allow(missing_docs)] EV_FLAG0; #[allow(missing_docs)] @@ -211,15 +204,13 @@ libc_bitflags! { EV_NODATA; #[allow(missing_docs)] EV_ONESHOT; - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] #[allow(missing_docs)] EV_OOBAND; - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] #[allow(missing_docs)] EV_POLL; - #[cfg(any(target_os = "dragonfly", target_os = "freebsd", - target_os = "ios", target_os = "macos", - target_os = "netbsd", target_os = "openbsd"))] + #[cfg(bsd)] #[allow(missing_docs)] EV_RECEIPT; } @@ -231,7 +222,7 @@ libc_bitflags!( // that wouldn't simply be repeating the man page. #[allow(missing_docs)] pub struct FilterFlag: u32 { - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] #[allow(missing_docs)] NOTE_ABSOLUTE; #[allow(missing_docs)] @@ -247,45 +238,27 @@ libc_bitflags!( NOTE_EXEC; #[allow(missing_docs)] NOTE_EXIT; - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] #[allow(missing_docs)] NOTE_EXITSTATUS; #[allow(missing_docs)] NOTE_EXTEND; - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] + #[cfg(any(apple_targets, freebsdlike))] #[allow(missing_docs)] NOTE_FFAND; - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] + #[cfg(any(apple_targets, freebsdlike))] #[allow(missing_docs)] NOTE_FFCOPY; - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] + #[cfg(any(apple_targets, freebsdlike))] #[allow(missing_docs)] NOTE_FFCTRLMASK; - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] + #[cfg(any(apple_targets, freebsdlike))] #[allow(missing_docs)] NOTE_FFLAGSMASK; - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] + #[cfg(any(apple_targets, freebsdlike))] #[allow(missing_docs)] NOTE_FFNOP; - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] + #[cfg(any(apple_targets, freebsdlike))] #[allow(missing_docs)] NOTE_FFOR; #[allow(missing_docs)] @@ -297,10 +270,12 @@ libc_bitflags!( #[cfg(target_os = "freebsd")] #[allow(missing_docs)] NOTE_MSECONDS; - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] #[allow(missing_docs)] NOTE_NONE; - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))] + #[cfg(any( + apple_targets, + target_os = "freebsd"))] #[allow(missing_docs)] NOTE_NSECONDS; #[cfg(target_os = "dragonfly")] @@ -314,38 +289,39 @@ libc_bitflags!( NOTE_RENAME; #[allow(missing_docs)] NOTE_REVOKE; - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))] + #[cfg(any( + apple_targets, + target_os = "freebsd"))] #[allow(missing_docs)] NOTE_SECONDS; - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] #[allow(missing_docs)] NOTE_SIGNAL; #[allow(missing_docs)] NOTE_TRACK; #[allow(missing_docs)] NOTE_TRACKERR; - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] + #[cfg(any(apple_targets, freebsdlike))] #[allow(missing_docs)] NOTE_TRIGGER; #[cfg(target_os = "openbsd")] #[allow(missing_docs)] NOTE_TRUNCATE; - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))] + #[cfg(any( + apple_targets, + target_os = "freebsd"))] #[allow(missing_docs)] NOTE_USECONDS; - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] #[allow(missing_docs)] NOTE_VM_ERROR; - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] #[allow(missing_docs)] NOTE_VM_PRESSURE; - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] #[allow(missing_docs)] NOTE_VM_PRESSURE_SUDDEN_TERMINATE; - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] #[allow(missing_docs)] NOTE_VM_PRESSURE_TERMINATE; #[allow(missing_docs)] @@ -443,13 +419,7 @@ pub fn kevent( kq.kevent(changelist, eventlist, Some(timeout)) } -#[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "openbsd" -))] +#[cfg(any(apple_targets, freebsdlike, target_os = "openbsd"))] type type_of_nchanges = c_int; #[cfg(target_os = "netbsd")] type type_of_nchanges = size_t; @@ -484,42 +454,3 @@ pub fn ev_set( 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/third_party/rust/nix/src/sys/eventfd.rs b/third_party/rust/nix/src/sys/eventfd.rs index f1723519cf..50a4f091bd 100644 --- a/third_party/rust/nix/src/sys/eventfd.rs +++ b/third_party/rust/nix/src/sys/eventfd.rs @@ -1,17 +1,84 @@ use crate::errno::Errno; -use crate::Result; -use std::os::unix::io::{FromRawFd, OwnedFd}; +use crate::{Result,unistd}; +use std::os::unix::io::{FromRawFd, OwnedFd, AsRawFd, AsFd, RawFd, BorrowedFd}; 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 + EFD_CLOEXEC; // Since Linux 2.6.27/FreeBSD 13.0 + EFD_NONBLOCK; // Since Linux 2.6.27/FreeBSD 13.0 + EFD_SEMAPHORE; // Since Linux 2.6.30/FreeBSD 13.0 } } +#[deprecated(since = "0.28.0", note = "Use EventFd::from_value_and_flags() instead")] pub fn eventfd(initval: libc::c_uint, flags: EfdFlags) -> Result<OwnedFd> { let res = unsafe { libc::eventfd(initval, flags.bits()) }; Errno::result(res).map(|r| unsafe { OwnedFd::from_raw_fd(r) }) } + +#[derive(Debug)] +#[repr(transparent)] +pub struct EventFd(OwnedFd); +impl EventFd { + /// [`EventFd::from_value_and_flags`] with `init_val = 0` and `flags = EfdFlags::empty()`. + pub fn new() -> Result<Self> { + Self::from_value_and_flags(0, EfdFlags::empty()) + } + /// Constructs [`EventFd`] with the given `init_val` and `flags`. + /// + /// Wrapper around [`libc::eventfd`]. + pub fn from_value_and_flags(init_val: u32, flags: EfdFlags) -> Result<Self> { + let res = unsafe { libc::eventfd(init_val, flags.bits()) }; + Errno::result(res).map(|r| Self(unsafe { OwnedFd::from_raw_fd(r) })) + } + /// [`EventFd::from_value_and_flags`] with `init_val = 0` and given `flags`. + pub fn from_flags(flags: EfdFlags) -> Result<Self> { + Self::from_value_and_flags(0, flags) + } + /// [`EventFd::from_value_and_flags`] with given `init_val` and `flags = EfdFlags::empty()`. + pub fn from_value(init_val: u32) -> Result<Self> { + Self::from_value_and_flags(init_val, EfdFlags::empty()) + } + /// Arms `self`, a following call to `poll`, `select` or `epoll` will return immediately. + /// + /// [`EventFd::write`] with `1`. + pub fn arm(&self) -> Result<usize> { + self.write(1) + } + /// Defuses `self`, a following call to `poll`, `select` or `epoll` will block. + /// + /// [`EventFd::write`] with `0`. + pub fn defuse(&self) -> Result<usize> { + self.write(0) + } + /// Enqueues `value` triggers. + /// + /// The next `value` calls to `poll`, `select` or `epoll` will return immediately. + /// + /// [`EventFd::write`] with `value`. + pub fn write(&self, value: u64) -> Result<usize> { + unistd::write(&self.0,&value.to_ne_bytes()) + } + // Reads the value from the file descriptor. + pub fn read(&self) -> Result<u64> { + let mut arr = [0; std::mem::size_of::<u64>()]; + unistd::read(self.0.as_raw_fd(),&mut arr)?; + Ok(u64::from_ne_bytes(arr)) + } +} +impl AsFd for EventFd { + fn as_fd(&self) -> BorrowedFd { + self.0.as_fd() + } +} +impl AsRawFd for EventFd { + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() + } +} +impl From<EventFd> for OwnedFd { + fn from(x: EventFd) -> OwnedFd { + x.0 + } +} diff --git a/third_party/rust/nix/src/sys/fanotify.rs b/third_party/rust/nix/src/sys/fanotify.rs new file mode 100644 index 0000000000..e217406e02 --- /dev/null +++ b/third_party/rust/nix/src/sys/fanotify.rs @@ -0,0 +1,416 @@ +//! Monitoring API for filesystem events. +//! +//! Fanotify is a Linux-only API to monitor filesystems events. +//! +//! Additional capabilities compared to the `inotify` API include the ability to +//! monitor all of the objects in a mounted filesystem, the ability to make +//! access permission decisions, and the possibility to read or modify files +//! before access by other applications. +//! +//! For more documentation, please read +//! [fanotify(7)](https://man7.org/linux/man-pages/man7/fanotify.7.html). + +use crate::errno::Errno; +use crate::fcntl::{at_rawfd, OFlag}; +use crate::unistd::{close, read, write}; +use crate::{NixPath, Result}; +use std::marker::PhantomData; +use std::mem::{size_of, MaybeUninit}; +use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd}; +use std::ptr; + +libc_bitflags! { + /// Mask for defining which events shall be listened with + /// [`fanotify_mark`](fn.fanotify_mark.html) and for querying notifications. + pub struct MaskFlags: u64 { + /// File was accessed. + FAN_ACCESS; + /// File was modified. + FAN_MODIFY; + /// Metadata has changed. Since Linux 5.1. + FAN_ATTRIB; + /// Writtable file was closed. + FAN_CLOSE_WRITE; + /// Unwrittable file was closed. + FAN_CLOSE_NOWRITE; + /// File was opened. + FAN_OPEN; + /// File was moved from X. Since Linux 5.1. + FAN_MOVED_FROM; + /// File was moved to Y. Since Linux 5.1. + FAN_MOVED_TO; + /// Subfile was created. Since Linux 5.1. + FAN_CREATE; + /// Subfile was deleted. Since Linux 5.1. + FAN_DELETE; + /// Self was deleted. Since Linux 5.1. + FAN_DELETE_SELF; + /// Self was moved. Since Linux 5.1. + FAN_MOVE_SELF; + /// File was opened for execution. Since Linux 5.0. + FAN_OPEN_EXEC; + + /// Event queue overflowed. + FAN_Q_OVERFLOW; + /// Filesystem error. Since Linux 5.16. + FAN_FS_ERROR; + + /// Permission to open file was requested. + FAN_OPEN_PERM; + /// Permission to access file was requested. + FAN_ACCESS_PERM; + /// Permission to open file for execution was requested. Since Linux + /// 5.0. + FAN_OPEN_EXEC_PERM; + + /// Interested in child events. + FAN_EVENT_ON_CHILD; + + /// File was renamed. Since Linux 5.17. + FAN_RENAME; + + /// Event occurred against dir. + FAN_ONDIR; + + /// Combination of `FAN_CLOSE_WRITE` and `FAN_CLOSE_NOWRITE`. + FAN_CLOSE; + /// Combination of `FAN_MOVED_FROM` and `FAN_MOVED_TO`. + FAN_MOVE; + } +} + +libc_bitflags! { + /// Configuration options for [`fanotify_init`](fn.fanotify_init.html). + pub struct InitFlags: libc::c_uint { + /// Close-on-exec flag set on the file descriptor. + FAN_CLOEXEC; + /// Nonblocking flag set on the file descriptor. + FAN_NONBLOCK; + + /// Receipt of events notifications. + FAN_CLASS_NOTIF; + /// Receipt of events for permission decisions, after they contain final + /// data. + FAN_CLASS_CONTENT; + /// Receipt of events for permission decisions, before they contain + /// final data. + FAN_CLASS_PRE_CONTENT; + + /// Remove the limit of 16384 events for the event queue. + FAN_UNLIMITED_QUEUE; + /// Remove the limit of 8192 marks. + FAN_UNLIMITED_MARKS; + + /// Make `FanotifyEvent::pid` return pidfd. Since Linux 5.15. + FAN_REPORT_PIDFD; + /// Make `FanotifyEvent::pid` return thread id. Since Linux 4.20. + FAN_REPORT_TID; + } +} + +libc_bitflags! { + /// File status flags for fanotify events file descriptors. + pub struct EventFFlags: libc::c_uint { + /// Read only access. + O_RDONLY as libc::c_uint; + /// Write only access. + O_WRONLY as libc::c_uint; + /// Read and write access. + O_RDWR as libc::c_uint; + /// Support for files exceeded 2 GB. + O_LARGEFILE as libc::c_uint; + /// Close-on-exec flag for the file descriptor. Since Linux 3.18. + O_CLOEXEC as libc::c_uint; + /// Append mode for the file descriptor. + O_APPEND as libc::c_uint; + /// Synchronized I/O data integrity completion. + O_DSYNC as libc::c_uint; + /// No file last access time update. + O_NOATIME as libc::c_uint; + /// Nonblocking mode for the file descriptor. + O_NONBLOCK as libc::c_uint; + /// Synchronized I/O file integrity completion. + O_SYNC as libc::c_uint; + } +} + +impl TryFrom<OFlag> for EventFFlags { + type Error = Errno; + + fn try_from(o_flag: OFlag) -> Result<Self> { + EventFFlags::from_bits(o_flag.bits() as u32).ok_or(Errno::EINVAL) + } +} + +impl From<EventFFlags> for OFlag { + fn from(event_f_flags: EventFFlags) -> Self { + OFlag::from_bits_retain(event_f_flags.bits() as i32) + } +} + +libc_bitflags! { + /// Configuration options for [`fanotify_mark`](fn.fanotify_mark.html). + pub struct MarkFlags: libc::c_uint { + /// Add the events to the marks. + FAN_MARK_ADD; + /// Remove the events to the marks. + FAN_MARK_REMOVE; + /// Don't follow symlinks, mark them. + FAN_MARK_DONT_FOLLOW; + /// Raise an error if filesystem to be marked is not a directory. + FAN_MARK_ONLYDIR; + /// Events added to or removed from the marks. + FAN_MARK_IGNORED_MASK; + /// Ignore mask shall survive modify events. + FAN_MARK_IGNORED_SURV_MODIFY; + /// Remove all marks. + FAN_MARK_FLUSH; + /// Do not pin inode object in the inode cache. Since Linux 5.19. + FAN_MARK_EVICTABLE; + /// Events added to or removed from the marks. Since Linux 6.0. + FAN_MARK_IGNORE; + + /// Default flag. + FAN_MARK_INODE; + /// Mark the mount specified by pathname. + FAN_MARK_MOUNT; + /// Mark the filesystem specified by pathname. Since Linux 4.20. + FAN_MARK_FILESYSTEM; + + /// Combination of `FAN_MARK_IGNORE` and `FAN_MARK_IGNORED_SURV_MODIFY`. + FAN_MARK_IGNORE_SURV; + } +} + +/// Compile version number of fanotify API. +pub const FANOTIFY_METADATA_VERSION: u8 = libc::FANOTIFY_METADATA_VERSION; + +/// Abstract over `libc::fanotify_event_metadata`, which represents an event +/// received via `Fanotify::read_events`. +// Is not Clone due to fd field, to avoid use-after-close scenarios. +#[derive(Debug, Eq, Hash, PartialEq)] +#[repr(transparent)] +#[allow(missing_copy_implementations)] +pub struct FanotifyEvent(libc::fanotify_event_metadata); + +impl FanotifyEvent { + /// Version number for the structure. It must be compared to + /// `FANOTIFY_METADATA_VERSION` to verify compile version and runtime + /// version does match. It can be done with the + /// `FanotifyEvent::check_version` method. + pub fn version(&self) -> u8 { + self.0.vers + } + + /// Checks that compile fanotify API version is equal to the version of the + /// event. + pub fn check_version(&self) -> bool { + self.version() == FANOTIFY_METADATA_VERSION + } + + /// Mask flags of the events. + pub fn mask(&self) -> MaskFlags { + MaskFlags::from_bits_truncate(self.0.mask) + } + + /// The file descriptor of the event. If the value is `None` when reading + /// from the fanotify group, this event is to notify that a group queue + /// overflow occured. + pub fn fd(&self) -> Option<BorrowedFd> { + if self.0.fd == libc::FAN_NOFD { + None + } else { + // SAFETY: self.0.fd will be opened for the lifetime of `Self`, + // which is longer than the lifetime of the returned BorrowedFd, so + // it is safe. + Some(unsafe { BorrowedFd::borrow_raw(self.0.fd) }) + } + } + + /// PID of the process that caused the event. TID in case flag + /// `FAN_REPORT_TID` was set at group initialization. + pub fn pid(&self) -> i32 { + self.0.pid + } +} + +impl Drop for FanotifyEvent { + fn drop(&mut self) { + let e = close(self.0.fd); + if !std::thread::panicking() && e == Err(Errno::EBADF) { + panic!("Closing an invalid file descriptor!"); + }; + } +} + +/// Abstraction over the structure to be sent to allow or deny a given event. +#[derive(Debug)] +#[repr(transparent)] +pub struct FanotifyResponse<'a> { + inner: libc::fanotify_response, + _borrowed_fd: PhantomData<BorrowedFd<'a>>, +} + +impl<'a> FanotifyResponse<'a> { + /// Create a new response. + pub fn new(fd: BorrowedFd<'a>, response: Response) -> Self { + Self { + inner: libc::fanotify_response { + fd: fd.as_raw_fd(), + response: response.bits(), + }, + _borrowed_fd: PhantomData, + } + } +} + +libc_bitflags! { + /// Response to be wrapped in `FanotifyResponse` and sent to the `Fanotify` + /// group to allow or deny an event. + pub struct Response: u32 { + /// Allow the event. + FAN_ALLOW; + /// Deny the event. + FAN_DENY; + } +} + +/// A fanotify group. This is also a file descriptor that can feed to other +/// interfaces consuming file descriptors. +#[derive(Debug)] +pub struct Fanotify { + fd: OwnedFd, +} + +impl Fanotify { + /// Initialize a new fanotify group. + /// + /// Returns a Result containing a Fanotify instance. + /// + /// For more information, see [fanotify_init(2)](https://man7.org/linux/man-pages/man7/fanotify_init.2.html). + pub fn init( + flags: InitFlags, + event_f_flags: EventFFlags, + ) -> Result<Fanotify> { + let res = Errno::result(unsafe { + libc::fanotify_init(flags.bits(), event_f_flags.bits()) + }); + res.map(|fd| Fanotify { + fd: unsafe { OwnedFd::from_raw_fd(fd) }, + }) + } + + /// Add, remove, or modify an fanotify mark on a filesystem object. + /// If `dirfd` is `None`, `AT_FDCWD` is used. + /// + /// Returns a Result containing either `()` on success or errno otherwise. + /// + /// For more information, see [fanotify_mark(2)](https://man7.org/linux/man-pages/man7/fanotify_mark.2.html). + pub fn mark<P: ?Sized + NixPath>( + &self, + flags: MarkFlags, + mask: MaskFlags, + dirfd: Option<RawFd>, + path: Option<&P>, + ) -> 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(path, |p| unsafe { + libc::fanotify_mark( + self.fd.as_raw_fd(), + flags.bits(), + mask.bits(), + at_rawfd(dirfd), + p, + ) + })?; + + Errno::result(res).map(|_| ()) + } + + /// Read incoming events from the fanotify group. + /// + /// Returns a Result containing either a `Vec` of events on success or errno + /// otherwise. + /// + /// # Errors + /// + /// Possible errors can be those that are explicitly listed in + /// [fanotify(2)](https://man7.org/linux/man-pages/man7/fanotify.2.html) in + /// addition to the possible errors caused by `read` call. + /// In particular, `EAGAIN` is returned when no event is available on a + /// group that has been initialized with the flag `InitFlags::FAN_NONBLOCK`, + /// thus making this method nonblocking. + pub fn read_events(&self) -> Result<Vec<FanotifyEvent>> { + let metadata_size = size_of::<libc::fanotify_event_metadata>(); + const BUFSIZ: usize = 4096; + let mut buffer = [0u8; BUFSIZ]; + let mut events = Vec::new(); + let mut offset = 0; + + let nread = read(self.fd.as_raw_fd(), &mut buffer)?; + + while (nread - offset) >= metadata_size { + let metadata = unsafe { + let mut metadata = + MaybeUninit::<libc::fanotify_event_metadata>::uninit(); + ptr::copy_nonoverlapping( + buffer.as_ptr().add(offset), + metadata.as_mut_ptr().cast(), + (BUFSIZ - offset).min(metadata_size), + ); + metadata.assume_init() + }; + + events.push(FanotifyEvent(metadata)); + offset += metadata.event_len as usize; + } + + Ok(events) + } + + /// Write an event response on the fanotify group. + /// + /// Returns a Result containing either `()` on success or errno otherwise. + /// + /// # Errors + /// + /// Possible errors can be those that are explicitly listed in + /// [fanotify(2)](https://man7.org/linux/man-pages/man7/fanotify.2.html) in + /// addition to the possible errors caused by `write` call. + /// In particular, `EAGAIN` or `EWOULDBLOCK` is returned when no event is + /// available on a group that has been initialized with the flag + /// `InitFlags::FAN_NONBLOCK`, thus making this method nonblocking. + pub fn write_response(&self, response: FanotifyResponse) -> Result<()> { + write(self.fd.as_fd(), unsafe { + std::slice::from_raw_parts( + (&response.inner as *const libc::fanotify_response).cast(), + size_of::<libc::fanotify_response>(), + ) + })?; + Ok(()) + } +} + +impl FromRawFd for Fanotify { + unsafe fn from_raw_fd(fd: RawFd) -> Self { + Fanotify { + fd: unsafe { OwnedFd::from_raw_fd(fd) }, + } + } +} + +impl AsFd for Fanotify { + fn as_fd(&'_ self) -> BorrowedFd<'_> { + self.fd.as_fd() + } +} diff --git a/third_party/rust/nix/src/sys/inotify.rs b/third_party/rust/nix/src/sys/inotify.rs index e5fe930f49..9cbeb53973 100644 --- a/third_party/rust/nix/src/sys/inotify.rs +++ b/third_party/rust/nix/src/sys/inotify.rs @@ -143,7 +143,9 @@ impl Inotify { pub fn init(flags: InitFlags) -> Result<Inotify> { let res = Errno::result(unsafe { libc::inotify_init1(flags.bits()) }); - res.map(|fd| Inotify { fd: unsafe { OwnedFd::from_raw_fd(fd) } }) + res.map(|fd| Inotify { + fd: unsafe { OwnedFd::from_raw_fd(fd) }, + }) } /// Adds a new watch on the target file or directory. @@ -157,7 +159,11 @@ impl Inotify { mask: AddWatchFlags, ) -> Result<WatchDescriptor> { let res = path.with_nix_path(|cstr| unsafe { - libc::inotify_add_watch(self.fd.as_raw_fd(), cstr.as_ptr(), mask.bits()) + libc::inotify_add_watch( + self.fd.as_raw_fd(), + cstr.as_ptr(), + mask.bits(), + ) })?; Errno::result(res).map(|wd| WatchDescriptor { wd }) @@ -202,7 +208,7 @@ impl Inotify { let mut event = MaybeUninit::<libc::inotify_event>::uninit(); ptr::copy_nonoverlapping( buffer.as_ptr().add(offset), - event.as_mut_ptr() as *mut u8, + event.as_mut_ptr().cast(), (BUFSIZ - offset).min(header_size), ); event.assume_init() @@ -237,7 +243,9 @@ impl Inotify { impl FromRawFd for Inotify { unsafe fn from_raw_fd(fd: RawFd) -> Self { - Inotify { fd: OwnedFd::from_raw_fd(fd) } + Inotify { + fd: unsafe { OwnedFd::from_raw_fd(fd) }, + } } } diff --git a/third_party/rust/nix/src/sys/ioctl/bsd.rs b/third_party/rust/nix/src/sys/ioctl/bsd.rs index 307994cb96..cedc8e63fe 100644 --- a/third_party/rust/nix/src/sys/ioctl/bsd.rs +++ b/third_party/rust/nix/src/sys/ioctl/bsd.rs @@ -1,10 +1,10 @@ /// The datatype used for the ioctl number #[doc(hidden)] -#[cfg(not(target_os = "illumos"))] +#[cfg(not(solarish))] pub type ioctl_num_type = ::libc::c_ulong; #[doc(hidden)] -#[cfg(target_os = "illumos")] +#[cfg(solarish)] pub type ioctl_num_type = ::libc::c_int; /// The datatype used for the 3rd argument diff --git a/third_party/rust/nix/src/sys/ioctl/linux.rs b/third_party/rust/nix/src/sys/ioctl/linux.rs index 610b8ddac0..52312f4f04 100644 --- a/third_party/rust/nix/src/sys/ioctl/linux.rs +++ b/third_party/rust/nix/src/sys/ioctl/linux.rs @@ -19,7 +19,9 @@ pub const TYPEBITS: ioctl_num_type = 8; cfg_if! { if #[cfg(any( target_arch = "mips", + target_arch = "mips32r6", target_arch = "mips64", + target_arch = "mips64r6", target_arch = "powerpc", target_arch = "powerpc64", target_arch = "sparc64" diff --git a/third_party/rust/nix/src/sys/ioctl/mod.rs b/third_party/rust/nix/src/sys/ioctl/mod.rs index 0b3fe3e769..e1e808f19e 100644 --- a/third_party/rust/nix/src/sys/ioctl/mod.rs +++ b/third_party/rust/nix/src/sys/ioctl/mod.rs @@ -72,7 +72,7 @@ //! # 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); +//! let res = unsafe { libc::ioctl(fd, request_code_read!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, mem::size_of::<u8>()), data) }; //! Errno::result(res) //! } //! # fn main() {} @@ -121,11 +121,11 @@ //! //! ``` //! # #[macro_use] extern crate nix; -//! # #[cfg(any(target_os = "android", target_os = "linux"))] +//! # #[cfg(linux_android)] //! # use nix::libc::TCGETS as TCGETS; -//! # #[cfg(any(target_os = "android", target_os = "linux"))] +//! # #[cfg(linux_android)] //! # use nix::libc::termios as termios; -//! # #[cfg(any(target_os = "android", target_os = "linux"))] +//! # #[cfg(linux_android)] //! ioctl_read_bad!(tcgets, TCGETS, termios); //! # fn main() {} //! ``` @@ -179,9 +179,13 @@ //! # 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); +//! let res = unsafe { +//! 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() {} @@ -223,40 +227,18 @@ //! ``` use cfg_if::cfg_if; -#[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] +#[cfg(any(linux_android, target_os = "redox"))] #[macro_use] mod linux; -#[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "redox" -))] +#[cfg(any(linux_android, 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" -))] +#[cfg(any(bsd, solarish, target_os = "haiku",))] #[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" -))] +#[cfg(any(bsd, solarish, target_os = "haiku",))] pub use self::bsd::*; /// Convert raw ioctl return value to a Nix result @@ -305,7 +287,9 @@ macro_rules! ioctl_none { $(#[$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)) + unsafe { + convert_ioctl_res!($crate::libc::ioctl(fd, request_code_none!($ioty, $nr) as $crate::sys::ioctl::ioctl_num_type)) + } } ) } @@ -345,7 +329,9 @@ macro_rules! ioctl_none_bad { $(#[$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)) + unsafe { + convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type)) + } } ) } @@ -383,7 +369,9 @@ macro_rules! ioctl_read { 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)) + unsafe { + 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)) + } } ) } @@ -408,7 +396,7 @@ macro_rules! ioctl_read { /// /// ``` /// # #[macro_use] extern crate nix; -/// # #[cfg(any(target_os = "android", target_os = "linux"))] +/// # #[cfg(linux_android)] /// ioctl_read_bad!(tcgets, libc::TCGETS, libc::termios); /// # fn main() {} /// ``` @@ -419,7 +407,9 @@ macro_rules! ioctl_read_bad { 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)) + unsafe { + convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data)) + } } ) } @@ -456,7 +446,9 @@ macro_rules! ioctl_write_ptr { 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)) + unsafe { + 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)) + } } ) } @@ -481,7 +473,7 @@ macro_rules! ioctl_write_ptr { /// /// ``` /// # #[macro_use] extern crate nix; -/// # #[cfg(any(target_os = "android", target_os = "linux"))] +/// # #[cfg(linux_android)] /// ioctl_write_ptr_bad!(tcsets, libc::TCSETS, libc::termios); /// # fn main() {} /// ``` @@ -492,13 +484,15 @@ macro_rules! ioctl_write_ptr_bad { 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)) + unsafe { + 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"))] { + if #[cfg(freebsdlike)] { /// Generates a wrapper function for a ioctl that writes an integer to the kernel. /// /// The arguments to this macro are: @@ -533,7 +527,9 @@ cfg_if! { 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)) + unsafe { + convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write_int!($ioty, $nr) as $crate::sys::ioctl::ioctl_num_type, data)) + } } ) } @@ -574,7 +570,9 @@ cfg_if! { 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)) + unsafe { + 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)) + } } ) } @@ -600,7 +598,7 @@ cfg_if! { /// /// ``` /// # #[macro_use] extern crate nix; -/// # #[cfg(any(target_os = "android", target_os = "linux"))] +/// # #[cfg(linux_android)] /// ioctl_write_int_bad!(tcsbrk, libc::TCSBRK); /// # fn main() {} /// ``` @@ -618,7 +616,9 @@ macro_rules! ioctl_write_int_bad { 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)) + unsafe { + convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data)) + } } ) } @@ -655,7 +655,9 @@ macro_rules! ioctl_readwrite { 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)) + unsafe { + 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)) + } } ) } @@ -683,7 +685,9 @@ macro_rules! ioctl_readwrite_bad { 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)) + unsafe { + convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data)) + } } ) } @@ -712,7 +716,9 @@ macro_rules! ioctl_read_buf { 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_val(data)) as $crate::sys::ioctl::ioctl_num_type, data)) + unsafe { + convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, ::std::mem::size_of_val(data)) as $crate::sys::ioctl::ioctl_num_type, data.as_mut_ptr())) + } } ) } @@ -751,7 +757,9 @@ macro_rules! ioctl_write_buf { 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, ::std::mem::size_of_val(data)) as $crate::sys::ioctl::ioctl_num_type, data)) + unsafe { + convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of_val(data)) as $crate::sys::ioctl::ioctl_num_type, data.as_ptr())) + } } ) } @@ -780,7 +788,9 @@ macro_rules! ioctl_readwrite_buf { 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_val(data)) as $crate::sys::ioctl::ioctl_num_type, data)) + unsafe { + convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, ::std::mem::size_of_val(data)) as $crate::sys::ioctl::ioctl_num_type, data.as_mut_ptr())) + } } ) } diff --git a/third_party/rust/nix/src/sys/memfd.rs b/third_party/rust/nix/src/sys/memfd.rs index 516ffd3262..22ee5fc5b7 100644 --- a/third_party/rust/nix/src/sys/memfd.rs +++ b/third_party/rust/nix/src/sys/memfd.rs @@ -29,6 +29,49 @@ libc_bitflags!( /// /// [`memfd_create(2)`]: https://man7.org/linux/man-pages/man2/memfd_create.2.html MFD_ALLOW_SEALING; + /// Anonymous file will be created using huge pages. It should be safe now to + /// combine with [`MFD_ALLOW_SEALING`] too. + /// However, despite its presence, on FreeBSD it is unimplemented for now (ENOSYS). + /// + /// See also the hugetlb filesystem in [`memfd_create(2)`]. + /// + /// [`memfd_create(2)`]: https://man7.org/linux/man-pages/man2/memfd_create.2.html + #[cfg(linux_android)] + MFD_HUGETLB; + /// Following are to be used with [`MFD_HUGETLB`], indicating the desired hugetlb size. + /// + /// See also the hugetlb filesystem in [`memfd_create(2)`]. + /// + /// [`memfd_create(2)`]: https://man7.org/linux/man-pages/man2/memfd_create.2.html + #[cfg(linux_android)] + MFD_HUGE_1MB; + /// hugetlb size of 2MB. + #[cfg(linux_android)] + MFD_HUGE_2MB; + /// hugetlb size of 8MB. + #[cfg(linux_android)] + MFD_HUGE_8MB; + /// hugetlb size of 16MB. + #[cfg(linux_android)] + MFD_HUGE_16MB; + /// hugetlb size of 32MB. + #[cfg(linux_android)] + MFD_HUGE_32MB; + /// hugetlb size of 256MB. + #[cfg(linux_android)] + MFD_HUGE_256MB; + /// hugetlb size of 512MB. + #[cfg(linux_android)] + MFD_HUGE_512MB; + /// hugetlb size of 1GB. + #[cfg(linux_android)] + MFD_HUGE_1GB; + /// hugetlb size of 2GB. + #[cfg(linux_android)] + MFD_HUGE_2GB; + /// hugetlb size of 16GB. + #[cfg(linux_android)] + MFD_HUGE_16GB; } ); diff --git a/third_party/rust/nix/src/sys/mman.rs b/third_party/rust/nix/src/sys/mman.rs index 8cfd6d6d54..a64f14f588 100644 --- a/third_party/rust/nix/src/sys/mman.rs +++ b/third_party/rust/nix/src/sys/mman.rs @@ -8,7 +8,11 @@ use crate::Result; #[cfg(feature = "fs")] use crate::{fcntl::OFlag, sys::stat::Mode}; use libc::{self, c_int, c_void, off_t, size_t}; -use std::{num::NonZeroUsize, os::unix::io::{AsRawFd, AsFd}}; +use std::ptr::NonNull; +use std::{ + num::NonZeroUsize, + os::unix::io::{AsFd, AsRawFd}, +}; libc_bitflags! { /// Desired memory protection of a memory mapping. @@ -22,12 +26,10 @@ libc_bitflags! { /// 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())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] PROT_GROWSUP; } } @@ -45,145 +47,143 @@ libc_bitflags! { 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"), + #[cfg(any(all(linux_android, 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())))] + #[cfg(linux_android)] MAP_GROWSDOWN; /// Compatibility flag. Ignored. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] MAP_DENYWRITE; /// Compatibility flag. Ignored. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] 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", target_os = "aix")))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(not(any(freebsdlike, target_os = "aix", target_os = "hurd")))] MAP_NORESERVE; /// Populate page tables for a mapping. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] MAP_NONBLOCK; /// Allocate the mapping using "huge pages." - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] 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())))] + #[cfg(freebsdlike)] 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())))] + #[cfg(netbsdlike)] 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())))] + #[cfg(any(freebsdlike, netbsdlike))] 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())))] + #[cfg(any(linux_android, freebsdlike, target_os = "openbsd"))] 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())))] + #[cfg(apple_targets)] 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())))] + #[cfg(apple_targets)] 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; + /// Attempt to place the mapping at exactly the address specified in `addr`. + /// it's a default behavior on OpenBSD. + #[cfg(netbsdlike)] + MAP_TRYFIXED; + } +} + +impl MapFlags { + /// Create `MAP_HUGETLB` with provided size of huge page. + /// + /// Under the hood it computes `MAP_HUGETLB | (huge_page_size_log2 << libc::MAP_HUGE_SHIFT`). + /// `huge_page_size_log2` denotes logarithm of huge page size to use and should be + /// between 16 and 63 (inclusively). + /// + /// ``` + /// # use nix::sys::mman::MapFlags; + /// let f = MapFlags::map_hugetlb_with_size_log2(30).unwrap(); + /// assert_eq!(f, MapFlags::MAP_HUGETLB | MapFlags::MAP_HUGE_1GB); + /// ``` + #[cfg(any(linux_android, target_os = "fuchsia"))] + pub fn map_hugetlb_with_size_log2( + huge_page_size_log2: u32, + ) -> Option<Self> { + if (16..=63).contains(&huge_page_size_log2) { + let flag = libc::MAP_HUGETLB + | (huge_page_size_log2 << libc::MAP_HUGE_SHIFT) as i32; + Some(Self(flag.into())) + } else { + None + } } } @@ -193,19 +193,15 @@ libc_bitflags! { 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; } } @@ -228,30 +224,24 @@ libc_enum! { /// 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())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] MADV_DONTFORK, /// Undo the effect of `MADV_DONTFORK`. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] MADV_MERGEABLE, /// Undo the effect of `MADV_MERGEABLE` - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] MADV_UNMERGEABLE, /// Preserve the memory of each page but offline the original page. #[cfg(any(target_os = "android", @@ -266,68 +256,52 @@ libc_enum! { 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())))] + #[cfg(linux_android)] MADV_HUGEPAGE, /// Undo the effect of `MADV_HUGEPAGE`. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] MADV_NOHUGEPAGE, /// Exclude the given range from a core dump. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] MADV_DONTDUMP, /// Undo the effect of an earlier `MADV_DONTDUMP`. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] MADV_DODUMP, /// Specify that the application no longer needs the pages in the given range. - #[cfg(not(target_os = "aix"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(not(any(target_os = "aix", target_os = "hurd")))] 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())))] + #[cfg(freebsdlike)] 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())))] + #[cfg(freebsdlike)] MADV_AUTOSYNC, /// Region is not included in a core file. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] MADV_NOCORE, /// Include region in a core file - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] 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())))] + #[cfg(apple_targets)] MADV_ZERO_WIRED_PAGES, /// Pages can be reused (by anyone). - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(apple_targets)] MADV_FREE_REUSABLE, /// Caller wants to reuse those pages. - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(apple_targets)] 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())))] + #[cfg(apple_targets)] #[allow(missing_docs)] MADV_CAN_REUSE, } @@ -341,12 +315,10 @@ libc_bitflags! { /// 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())))] + #[cfg(apple_targets)] MS_KILLPAGES; /// Deactivate pages, but leave them mapped. - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(apple_targets)] MS_DEACTIVATE; /// Perform an update and wait for it to complete. MS_SYNC; @@ -374,8 +346,8 @@ libc_bitflags! { /// `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) +pub unsafe fn mlock(addr: NonNull<c_void>, length: size_t) -> Result<()> { + unsafe { Errno::result(libc::mlock(addr.as_ptr(), length)).map(drop) } } /// Unlocks all memory pages that contain part of the address range with @@ -387,8 +359,8 @@ pub unsafe fn mlock(addr: *const c_void, length: size_t) -> Result<()> { /// 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) +pub unsafe fn munlock(addr: NonNull<c_void>, length: size_t) -> Result<()> { + unsafe { Errno::result(libc::munlock(addr.as_ptr(), length)).map(drop) } } /// Locks all memory pages mapped into this process' address space. @@ -411,7 +383,9 @@ pub fn munlockall() -> Result<()> { unsafe { Errno::result(libc::munlockall()) }.map(drop) } -/// allocate memory, or map files or devices into memory +/// Allocate memory, or map files or devices into memory +/// +/// For anonymous mappings (`MAP_ANON`/`MAP_ANONYMOUS`), see [mmap_anonymous]. /// /// # Safety /// @@ -423,20 +397,54 @@ pub unsafe fn mmap<F: AsFd>( length: NonZeroUsize, prot: ProtFlags, flags: MapFlags, - f: Option<F>, + f: F, offset: off_t, -) -> Result<*mut c_void> { - let ptr = - addr.map_or(std::ptr::null_mut(), |a| usize::from(a) as *mut c_void); +) -> Result<NonNull<c_void>> { + let ptr = addr.map_or(std::ptr::null_mut(), |a| a.get() as *mut c_void); - let fd = f.map(|f| f.as_fd().as_raw_fd()).unwrap_or(-1); - let ret = - libc::mmap(ptr, length.into(), prot.bits(), flags.bits(), fd, offset); + let fd = f.as_fd().as_raw_fd(); + let ret = unsafe { + libc::mmap(ptr, length.into(), prot.bits(), flags.bits(), fd, offset) + }; + + if ret == libc::MAP_FAILED { + Err(Errno::last()) + } else { + // SAFETY: `libc::mmap` returns a valid non-null pointer or `libc::MAP_FAILED`, thus `ret` + // will be non-null here. + Ok(unsafe { NonNull::new_unchecked(ret) }) + } +} + +/// Create an anonymous memory mapping. +/// +/// This function is a wrapper around [`mmap`]: +/// `mmap(ptr, len, prot, MAP_ANONYMOUS | flags, -1, 0)`. +/// +/// # 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_anonymous( + addr: Option<NonZeroUsize>, + length: NonZeroUsize, + prot: ProtFlags, + flags: MapFlags, +) -> Result<NonNull<c_void>> { + let ptr = addr.map_or(std::ptr::null_mut(), |a| a.get() as *mut c_void); + + let flags = MapFlags::MAP_ANONYMOUS | flags; + let ret = unsafe { + libc::mmap(ptr, length.into(), prot.bits(), flags.bits(), -1, 0) + }; if ret == libc::MAP_FAILED { Err(Errno::last()) } else { - Ok(ret) + // SAFETY: `libc::mmap` returns a valid non-null pointer or `libc::MAP_FAILED`, thus `ret` + // will be non-null here. + Ok(unsafe { NonNull::new_unchecked(ret) }) } } @@ -449,33 +457,43 @@ pub unsafe fn mmap<F: AsFd>( /// detailed requirements. #[cfg(any(target_os = "linux", target_os = "netbsd"))] pub unsafe fn mremap( - addr: *mut c_void, + addr: NonNull<c_void>, old_size: size_t, new_size: size_t, flags: MRemapFlags, - new_address: Option<*mut c_void>, -) -> Result<*mut c_void> { + new_address: Option<NonNull<c_void>>, +) -> Result<NonNull<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()), - ); + let ret = unsafe { + libc::mremap( + addr.as_ptr(), + old_size, + new_size, + flags.bits(), + new_address + .map(NonNull::as_ptr) + .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(), - ); + let ret = unsafe { + libc::mremap( + addr.as_ptr(), + old_size, + new_address + .map(NonNull::as_ptr) + .unwrap_or(std::ptr::null_mut()), + new_size, + flags.bits(), + ) + }; if ret == libc::MAP_FAILED { Err(Errno::last()) } else { - Ok(ret) + // SAFETY: `libc::mremap` returns a valid non-null pointer or `libc::MAP_FAILED`, thus `ret` + // will be non-null here. + Ok(unsafe { NonNull::new_unchecked(ret) }) } } @@ -487,8 +505,8 @@ pub unsafe fn mremap( /// 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) +pub unsafe fn munmap(addr: NonNull<c_void>, len: size_t) -> Result<()> { + unsafe { Errno::result(libc::munmap(addr.as_ptr(), len)).map(drop) } } /// give advice about use of memory @@ -499,12 +517,16 @@ pub unsafe fn munmap(addr: *mut c_void, len: size_t) -> Result<()> { /// [`MmapAdvise::MADV_FREE`]. /// /// [`madvise(2)`]: https://man7.org/linux/man-pages/man2/madvise.2.html +#[allow(rustdoc::broken_intra_doc_links)] // For Hurd as `MADV_FREE` is not available on it pub unsafe fn madvise( - addr: *mut c_void, + addr: NonNull<c_void>, length: size_t, advise: MmapAdvise, ) -> Result<()> { - Errno::result(libc::madvise(addr, length, advise as i32)).map(drop) + unsafe { + Errno::result(libc::madvise(addr.as_ptr(), length, advise as i32)) + .map(drop) + } } /// Set protection of memory mapping. @@ -519,27 +541,30 @@ pub unsafe fn madvise( /// /// ``` /// # use nix::libc::size_t; -/// # use nix::sys::mman::{mmap, mprotect, MapFlags, ProtFlags}; +/// # use nix::sys::mman::{mmap_anonymous, mprotect, MapFlags, ProtFlags}; /// # use std::ptr; /// # use std::os::unix::io::BorrowedFd; /// 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::<BorrowedFd>(None, one_k_non_zero, ProtFlags::PROT_NONE, -/// MapFlags::MAP_ANON | MapFlags::MAP_PRIVATE, None, 0).unwrap(); +/// let mem = mmap_anonymous(None, one_k_non_zero, ProtFlags::PROT_NONE, MapFlags::MAP_PRIVATE) +/// .unwrap(); /// mprotect(mem, ONE_K, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE).unwrap(); -/// std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K) +/// std::slice::from_raw_parts_mut(mem.as_ptr().cast(), ONE_K) /// }; /// assert_eq!(slice[0], 0x00); /// slice[0] = 0xFF; /// assert_eq!(slice[0], 0xFF); /// ``` pub unsafe fn mprotect( - addr: *mut c_void, + addr: NonNull<c_void>, length: size_t, prot: ProtFlags, ) -> Result<()> { - Errno::result(libc::mprotect(addr, length, prot.bits())).map(drop) + unsafe { + Errno::result(libc::mprotect(addr.as_ptr(), length, prot.bits())) + .map(drop) + } } /// synchronize a mapped region @@ -551,11 +576,14 @@ pub unsafe fn mprotect( /// /// [`msync(2)`]: https://man7.org/linux/man-pages/man2/msync.2.html pub unsafe fn msync( - addr: *mut c_void, + addr: NonNull<c_void>, length: size_t, flags: MsFlags, ) -> Result<()> { - Errno::result(libc::msync(addr, length, flags.bits())).map(drop) + unsafe { + Errno::result(libc::msync(addr.as_ptr(), length, flags.bits())) + .map(drop) + } } #[cfg(not(target_os = "android"))] @@ -576,11 +604,11 @@ pub fn shm_open<P>( use std::os::unix::io::{FromRawFd, OwnedFd}; let ret = name.with_nix_path(|cstr| { - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] unsafe { libc::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as libc::c_uint) } - #[cfg(not(any(target_os = "macos", target_os = "ios")))] + #[cfg(not(apple_targets))] unsafe { libc::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as libc::mode_t) } diff --git a/third_party/rust/nix/src/sys/mod.rs b/third_party/rust/nix/src/sys/mod.rs index bf047b3dda..93339d1935 100644 --- a/third_party/rust/nix/src/sys/mod.rs +++ b/third_party/rust/nix/src/sys/mod.rs @@ -1,10 +1,8 @@ //! Mostly platform-specific functionality #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", + freebsdlike, all(target_os = "linux", not(target_env = "uclibc")), - target_os = "macos", + apple_targets, target_os = "netbsd" ))] feature! { @@ -15,41 +13,31 @@ feature! { feature! { #![feature = "event"] - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] #[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"))] + #[cfg(bsd)] pub mod event; - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(any(linux_android, target_os = "freebsd"))] #[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(target_os = "linux")] +feature! { + #![feature = "fanotify"] + pub mod fanotify; +} + +#[cfg(any(bsd, linux_android, target_os = "redox", solarish))] #[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"))] +#[cfg(any(linux_android, target_os = "freebsd"))] feature! { #![feature = "fs"] pub mod memfd; @@ -78,15 +66,7 @@ feature! { 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" -))] +#[cfg(any(linux_android, bsd))] feature! { #![feature = "ptrace"] #[allow(missing_docs)] @@ -99,7 +79,7 @@ feature! { pub mod quota; } -#[cfg(target_os = "linux")] +#[cfg(any(target_os = "linux", netbsdlike))] feature! { #![feature = "reboot"] pub mod reboot; @@ -108,7 +88,7 @@ feature! { #[cfg(not(any( target_os = "redox", target_os = "fuchsia", - target_os = "illumos", + solarish, target_os = "haiku" )))] feature! { @@ -121,14 +101,7 @@ feature! { pub mod select; } -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos" -))] +#[cfg(any(linux_android, freebsdlike, apple_targets, solarish))] feature! { #![feature = "zerocopy"] pub mod sendfile; @@ -136,7 +109,7 @@ feature! { pub mod signal; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] feature! { #![feature = "signal"] #[allow(missing_docs)] @@ -155,15 +128,7 @@ feature! { 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" -))] +#[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "openbsd"))] feature! { #![feature = "fs"] pub mod statfs; @@ -174,8 +139,7 @@ feature! { pub mod statvfs; } -#[cfg(any(target_os = "android", target_os = "linux"))] -#[cfg_attr(docsrs, doc(cfg(all())))] +#[cfg(linux_android)] #[allow(missing_docs)] pub mod sysinfo; @@ -203,13 +167,13 @@ feature! { pub mod wait; } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] feature! { #![feature = "inotify"] pub mod inotify; } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] feature! { #![feature = "time"] pub mod timerfd; @@ -218,7 +182,7 @@ feature! { #[cfg(all( any( target_os = "freebsd", - target_os = "illumos", + solarish, target_os = "linux", target_os = "netbsd" ), diff --git a/third_party/rust/nix/src/sys/personality.rs b/third_party/rust/nix/src/sys/personality.rs index 30231dd7b8..a4cfb5ef4f 100644 --- a/third_party/rust/nix/src/sys/personality.rs +++ b/third_party/rust/nix/src/sys/personality.rs @@ -21,7 +21,6 @@ libc_bitflags! { 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; @@ -43,7 +42,6 @@ libc_bitflags! { /// /// [`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; diff --git a/third_party/rust/nix/src/sys/prctl.rs b/third_party/rust/nix/src/sys/prctl.rs index 995382cb0c..42324beab2 100644 --- a/third_party/rust/nix/src/sys/prctl.rs +++ b/third_party/rust/nix/src/sys/prctl.rs @@ -50,7 +50,9 @@ pub fn get_child_subreaper() -> Result<bool> { // prctl writes into this var let mut subreaper: c_int = 0; - let res = unsafe { libc::prctl(libc::PR_GET_CHILD_SUBREAPER, &mut subreaper, 0, 0, 0) }; + let res = unsafe { + libc::prctl(libc::PR_GET_CHILD_SUBREAPER, &mut subreaper, 0, 0, 0) + }; Errno::result(res).map(|_| subreaper != 0) } @@ -78,7 +80,9 @@ pub fn get_keepcaps() -> Result<bool> { /// Clear the thread memory corruption kill policy and use the system-wide default pub fn clear_mce_kill() -> Result<()> { - let res = unsafe { libc::prctl(libc::PR_MCE_KILL, libc::PR_MCE_KILL_CLEAR, 0, 0, 0) }; + let res = unsafe { + libc::prctl(libc::PR_MCE_KILL, libc::PR_MCE_KILL_CLEAR, 0, 0, 0) + }; Errno::result(res).map(drop) } @@ -151,10 +155,11 @@ pub fn get_name() -> Result<CString> { let res = unsafe { libc::prctl(libc::PR_GET_NAME, &buf, 0, 0, 0) }; - let len = buf.iter().position(|&c| c == 0).unwrap_or(buf.len()); - let name = CStr::from_bytes_with_nul(&buf[..=len]).map_err(|_| Errno::EINVAL)?; - - Errno::result(res).map(|_| name.to_owned()) + Errno::result(res).and_then(|_| { + CStr::from_bytes_until_nul(&buf) + .map(CStr::to_owned) + .map_err(|_| Errno::EINVAL) + }) } /// Sets the timer slack value for the calling thread. Timer slack is used by the kernel to group @@ -174,14 +179,16 @@ pub fn get_timerslack() -> Result<i32> { /// Disable all performance counters attached to the calling process. pub fn task_perf_events_disable() -> Result<()> { - let res = unsafe { libc::prctl(libc::PR_TASK_PERF_EVENTS_DISABLE, 0, 0, 0, 0) }; + let res = + unsafe { libc::prctl(libc::PR_TASK_PERF_EVENTS_DISABLE, 0, 0, 0, 0) }; Errno::result(res).map(drop) } /// Enable all performance counters attached to the calling process. pub fn task_perf_events_enable() -> Result<()> { - let res = unsafe { libc::prctl(libc::PR_TASK_PERF_EVENTS_ENABLE, 0, 0, 0, 0) }; + let res = + unsafe { libc::prctl(libc::PR_TASK_PERF_EVENTS_ENABLE, 0, 0, 0, 0) }; Errno::result(res).map(drop) } diff --git a/third_party/rust/nix/src/sys/ptrace/bsd.rs b/third_party/rust/nix/src/sys/ptrace/bsd.rs index ba267c6577..3dd486210c 100644 --- a/third_party/rust/nix/src/sys/ptrace/bsd.rs +++ b/third_party/rust/nix/src/sys/ptrace/bsd.rs @@ -9,10 +9,7 @@ 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"))] { + if #[cfg(any(freebsdlike, apple_targets, target_os = "openbsd"))] { #[doc(hidden)] pub type AddressType = *mut ::libc::c_char; } else { @@ -29,33 +26,26 @@ libc_enum! { PT_TRACE_ME, PT_READ_I, PT_READ_D, - #[cfg(target_os = "macos")] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(apple_targets)] PT_READ_U, PT_WRITE_I, PT_WRITE_D, - #[cfg(target_os = "macos")] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(apple_targets)] PT_WRITE_U, PT_CONTINUE, PT_KILL, - #[cfg(any(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos"), + #[cfg(any(any(freebsdlike, apple_targets), 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())))] + #[cfg(apple_targets)] PT_SIGEXC, - #[cfg(target_os = "macos")] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(apple_targets)] PT_THUPDATE, - #[cfg(target_os = "macos")] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(apple_targets)] PT_ATTACHEXC } } @@ -66,13 +56,15 @@ unsafe fn ptrace_other( addr: AddressType, data: c_int, ) -> Result<c_int> { - Errno::result(libc::ptrace( - request as RequestType, - libc::pid_t::from(pid), - addr, - data, - )) - .map(|_| 0) + unsafe { + 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, ...)` @@ -157,7 +149,7 @@ pub fn kill(pid: Pid) -> Result<()> { /// } /// ``` #[cfg(any( - any(target_os = "dragonfly", target_os = "freebsd", target_os = "macos"), + any(freebsdlike, apple_targets), all(target_os = "openbsd", target_arch = "x86_64"), all( target_os = "netbsd", diff --git a/third_party/rust/nix/src/sys/ptrace/linux.rs b/third_party/rust/nix/src/sys/ptrace/linux.rs index 8c134cf7ee..26544e134b 100644 --- a/third_party/rust/nix/src/sys/ptrace/linux.rs +++ b/third_party/rust/nix/src/sys/ptrace/linux.rs @@ -53,28 +53,36 @@ libc_enum! { #[cfg(any(all(target_os = "android", target_pointer_width = "32"), all(target_os = "linux", any(target_env = "musl", target_arch = "mips", + target_arch = "mips32r6", target_arch = "mips64", + target_arch = "mips64r6", 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 = "mips32r6", target_arch = "mips64", + target_arch = "mips64r6", 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 = "mips32r6", target_arch = "mips64", + target_arch = "mips64r6", 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 = "mips32r6", target_arch = "mips64", + target_arch = "mips64r6", target_arch = "x86_64", target_pointer_width = "32"))))] PTRACE_SETFPREGS, @@ -82,13 +90,17 @@ libc_enum! { PTRACE_DETACH, #[cfg(all(target_os = "linux", any(target_env = "musl", target_arch = "mips", + target_arch = "mips32r6", target_arch = "mips64", + target_arch = "mips64r6", target_arch = "x86", target_arch = "x86_64")))] PTRACE_GETFPXREGS, #[cfg(all(target_os = "linux", any(target_env = "musl", target_arch = "mips", + target_arch = "mips32r6", target_arch = "mips64", + target_arch = "mips64r6", target_arch = "x86", target_arch = "x86_64")))] PTRACE_SETFPXREGS, @@ -98,22 +110,28 @@ libc_enum! { PTRACE_GETSIGINFO, PTRACE_SETSIGINFO, #[cfg(all(target_os = "linux", not(any(target_arch = "mips", - target_arch = "mips64"))))] + target_arch = "mips32r6", + target_arch = "mips64", + target_arch = "mips64r6"))))] PTRACE_GETREGSET, #[cfg(all(target_os = "linux", not(any(target_arch = "mips", - target_arch = "mips64"))))] + target_arch = "mips32r6", + target_arch = "mips64", + target_arch = "mips64r6"))))] 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"))))] + target_arch = "mips32r6", + target_arch = "mips64", + target_arch = "mips64r6"))))] PTRACE_LISTEN, #[cfg(all(target_os = "linux", not(any(target_arch = "mips", - target_arch = "mips64"))))] + target_arch = "mips32r6", + target_arch = "mips64", + target_arch = "mips64r6"))))] PTRACE_PEEKSIGINFO, #[cfg(all(target_os = "linux", target_env = "gnu", any(target_arch = "x86", target_arch = "x86_64")))] @@ -241,13 +259,13 @@ pub fn setregs(pid: Pid, regs: user_regs_struct) -> Result<()> { /// 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 mut data = mem::MaybeUninit::<T>::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, + data.as_mut_ptr(), ) }; Errno::result(res)?; @@ -260,13 +278,15 @@ unsafe fn ptrace_other( 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) + unsafe { + Errno::result(libc::ptrace( + request as RequestType, + libc::pid_t::from(pid), + addr, + data, + )) + .map(|_| 0) + } } /// Set options, as with `ptrace(PTRACE_SETOPTIONS, ...)`. @@ -381,7 +401,6 @@ pub fn attach(pid: Pid) -> Result<()> { /// /// 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( @@ -428,7 +447,6 @@ pub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { /// /// 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( @@ -535,7 +553,7 @@ pub unsafe fn write( addr: AddressType, data: *mut c_void, ) -> Result<()> { - ptrace_other(Request::PTRACE_POKEDATA, pid, addr, data).map(drop) + unsafe { ptrace_other(Request::PTRACE_POKEDATA, pid, addr, data).map(drop) } } /// Reads a word from a user area at `offset`, as with ptrace(PTRACE_PEEKUSER, ...). @@ -556,5 +574,7 @@ pub unsafe fn write_user( offset: AddressType, data: *mut c_void, ) -> Result<()> { - ptrace_other(Request::PTRACE_POKEUSER, pid, offset, data).map(drop) + unsafe { + ptrace_other(Request::PTRACE_POKEUSER, pid, offset, data).map(drop) + } } diff --git a/third_party/rust/nix/src/sys/ptrace/mod.rs b/third_party/rust/nix/src/sys/ptrace/mod.rs index 88648acabc..c059797df9 100644 --- a/third_party/rust/nix/src/sys/ptrace/mod.rs +++ b/third_party/rust/nix/src/sys/ptrace/mod.rs @@ -1,25 +1,13 @@ //! Provides helpers for making ptrace system calls -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] mod linux; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] pub use self::linux::*; -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" -))] +#[cfg(bsd)] mod bsd; -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" -))] +#[cfg(bsd)] pub use self::bsd::*; diff --git a/third_party/rust/nix/src/sys/quota.rs b/third_party/rust/nix/src/sys/quota.rs index a32d07aa1e..2d12b858bf 100644 --- a/third_party/rust/nix/src/sys/quota.rs +++ b/third_party/rust/nix/src/sys/quota.rs @@ -264,7 +264,7 @@ pub fn quotactl_on<P: ?Sized + NixPath>( ) -> 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; + let p: *mut c_char = path_copy.as_mut_ptr().cast(); quotactl( QuotaCmd(QuotaSubCmd::Q_QUOTAON, which), Some(special), @@ -308,12 +308,12 @@ pub fn quotactl_get<P: ?Sized + NixPath>( special: &P, id: c_int, ) -> Result<Dqblk> { - let mut dqblk = mem::MaybeUninit::uninit(); + let mut dqblk = mem::MaybeUninit::<libc::dqblk>::uninit(); quotactl( QuotaCmd(QuotaSubCmd::Q_GETQUOTA, which), Some(special), id, - dqblk.as_mut_ptr() as *mut c_char, + dqblk.as_mut_ptr().cast(), )?; Ok(unsafe { Dqblk(dqblk.assume_init()) }) } diff --git a/third_party/rust/nix/src/sys/reboot.rs b/third_party/rust/nix/src/sys/reboot.rs index 02d98162bd..2e4d888de4 100644 --- a/third_party/rust/nix/src/sys/reboot.rs +++ b/third_party/rust/nix/src/sys/reboot.rs @@ -1,48 +1,141 @@ -//! Reboot/shutdown or enable/disable Ctrl-Alt-Delete. +//! Reboot/shutdown +//! +//! On Linux, This can also be used to enable/disable Ctrl-Alt-Delete. use crate::errno::Errno; use crate::Result; +use cfg_if::cfg_if; 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()) -} +cfg_if! { + if #[cfg(target_os = "linux")] { + 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) + /// 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) + } + } else if #[cfg(netbsdlike)] { + use libc::c_int; + + libc_bitflags! { + /// How exactly should the system be rebooted. + pub struct RebootMode: c_int { + /// The default, causing the system to reboot in its usual fashion. + RB_AUTOBOOT; + /// Interpreted by the bootstrap program itself, causing it to + /// prompt on the console as to what file should be booted. + /// Normally, the system is booted from the file “xx(0,0)bsd”, + /// where xx is the default disk name, without prompting for + /// the file name. + RB_ASKNAME; + /// Dump kernel memory before rebooting; see `savecore(8)` for + /// more information. + RB_DUMP; + /// The processor is simply halted; no reboot takes place. + RB_HALT; + /// Power off the system if the system hardware supports the + /// function, otherwise it has no effect. + /// + /// Should be used in conjunction with `RB_HALT`. + RB_POWERDOWN; + /// By default, the system will halt if `reboot()` is called during + /// startup (before the system has finished autoconfiguration), even + /// if `RB_HALT` is not specified. This is because `panic(9)`s + /// during startup will probably just repeat on the next boot. + /// Use of this option implies that the user has requested the + /// action specified (for example, using the `ddb(4)` boot reboot + /// command), so the system will reboot if a halt is not explicitly + /// requested. + #[cfg(target_os = "openbsd")] + RB_USERREQ; + /// Load the symbol table and enable a built-in debugger in the + /// system. This option will have no useful function if the kernel + /// is not configured for debugging. Several other options have + /// different meaning if combined with this option, although their + /// use may not be possible via the `reboot()` call. See `ddb(4)` for + /// more information. + RB_KDB; + /// Normally, the disks are sync'd (see `sync(8)`) before the + /// processor is halted or rebooted. This option may be useful + /// if file system changes have been made manually or if the + /// processor is on fire. + RB_NOSYNC; + /// Normally, the reboot procedure involves an automatic disk + /// consistency check and then multi-user operations. `RB_SINGLE` + /// prevents this, booting the system with a single-user shell on + /// the console. `RB_SINGLE` is actually interpreted by the `init(8)` + /// program in the newly booted system. + /// + /// When no options are given (i.e., `RB_AUTOBOOT` is used), the + /// system is rebooted from file /bsd in the root file system of + /// unit 0 of a disk chosen in a processor specific way. An automatic + /// consistency check of the disks is normally performed (see `fsck(8)`). + RB_SINGLE; + /// Initially invoke the `userconf(4)` facility when the system + /// starts up again, if it has been compiled into the kernel + /// that is loaded. + #[cfg(target_os = "netbsd")] + RB_USERCONF; + /// Don't update the hardware clock from the system clock, presumably + /// because the system clock is suspect. + #[cfg(target_os = "openbsd")] + RB_TIMEBAD; + } + } + + /// Reboot system or halt processor + /// + /// For more information, see the man pages: + /// + /// * [NetBSD](https://man.netbsd.org/reboot.2) + /// * [OpenBSD](https://man.openbsd.org/reboot.2) + #[cfg(netbsdlike)] + pub fn reboot(how: RebootMode) -> Result<Infallible> { + #[cfg(target_os = "openbsd")] + unsafe { libc::reboot(how.bits()) }; + #[cfg(target_os = "netbsd")] + unsafe { libc::reboot(how.bits(), std::ptr::null_mut()) }; + + Err(Errno::last()) + } + } } + diff --git a/third_party/rust/nix/src/sys/resource.rs b/third_party/rust/nix/src/sys/resource.rs index f42d32e3ca..71315072d4 100644 --- a/third_party/rust/nix/src/sys/resource.rs +++ b/third_party/rust/nix/src/sys/resource.rs @@ -10,16 +10,14 @@ pub use libc::RLIM_INFINITY; use std::mem; cfg_if! { - if #[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))]{ + if #[cfg(any( + all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")), + target_os = "hurd" + ))]{ 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", + bsd, target_os = "android", - target_os = "dragonfly", target_os = "aix", all(target_os = "linux", not(target_env = "gnu")) ))]{ @@ -43,22 +41,19 @@ libc_enum! { // // 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", + all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")), + target_os = "hurd" + ), repr(u32))] + #[cfg_attr(any( + bsd, target_os = "android", - target_os = "dragonfly", target_os = "aix", 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())))] + #[cfg(not(any(target_os = "freebsd", netbsdlike)))] /// The maximum amount (in bytes) of virtual memory the process is /// allowed to map. RLIMIT_AS, @@ -77,102 +72,78 @@ libc_enum! { 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())))] + #[cfg(linux_android)] /// 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())))] + #[cfg(any(linux_android, target_os = "freebsd", netbsdlike))] /// 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())))] + #[cfg(linux_android)] /// 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())))] + #[cfg(linux_android)] /// A ceiling to which the process's nice value can be raised using /// setpriority or nice. RLIMIT_NICE, #[cfg(any( - target_os = "android", + linux_android, target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd", - target_os = "linux", + netbsdlike, target_os = "aix", ))] - #[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", + #[cfg(any(linux_android, target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd", - target_os = "linux", + netbsdlike, target_os = "aix", ))] - #[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())))] + #[cfg(linux_android)] /// 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())))] + #[cfg(linux_android)] /// 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())))] + #[cfg(freebsdlike)] /// 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, } @@ -206,7 +177,10 @@ 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")))]{ + if #[cfg(any( + all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")), + target_os = "hurd" + ))] { 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()) }; @@ -259,7 +233,10 @@ pub fn setrlimit( rlim_max: hard_limit, }; cfg_if! { - if #[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))]{ + if #[cfg(any( + all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")), + target_os = "hurd", + ))]{ 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) }; @@ -281,7 +258,6 @@ libc_enum! { 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, } @@ -420,28 +396,3 @@ pub fn getrusage(who: UsageWho) -> Result<Usage> { 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/third_party/rust/nix/src/sys/select.rs b/third_party/rust/nix/src/sys/select.rs index 0e2193b130..64a8e258cf 100644 --- a/third_party/rust/nix/src/sys/select.rs +++ b/third_party/rust/nix/src/sys/select.rs @@ -7,7 +7,7 @@ use std::convert::TryFrom; use std::iter::FusedIterator; use std::mem; use std::ops::Range; -use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd}; +use std::os::unix::io::{AsRawFd, BorrowedFd, RawFd}; use std::ptr::{null, null_mut}; pub use libc::FD_SETSIZE; @@ -41,21 +41,21 @@ impl<'fd> FdSet<'fd> { } /// Add a file descriptor to an `FdSet` - pub fn insert<Fd: AsFd>(&mut self, fd: &'fd Fd) { - assert_fd_valid(fd.as_fd().as_raw_fd()); - unsafe { libc::FD_SET(fd.as_fd().as_raw_fd(), &mut self.set) }; + pub fn insert(&mut self, fd: BorrowedFd<'fd>) { + assert_fd_valid(fd.as_raw_fd()); + unsafe { libc::FD_SET(fd.as_raw_fd(), &mut self.set) }; } /// Remove a file descriptor from an `FdSet` - pub fn remove<Fd: AsFd>(&mut self, fd: &'fd Fd) { - assert_fd_valid(fd.as_fd().as_raw_fd()); - unsafe { libc::FD_CLR(fd.as_fd().as_raw_fd(), &mut self.set) }; + pub fn remove(&mut self, fd: BorrowedFd<'fd>) { + assert_fd_valid(fd.as_raw_fd()); + unsafe { libc::FD_CLR(fd.as_raw_fd(), &mut self.set) }; } /// Test an `FdSet` for the presence of a certain file descriptor. - pub fn contains<Fd: AsFd>(&self, fd: &'fd Fd) -> bool { - assert_fd_valid(fd.as_fd().as_raw_fd()); - unsafe { libc::FD_ISSET(fd.as_fd().as_raw_fd(), &self.set) } + pub fn contains(&self, fd: BorrowedFd<'fd>) -> bool { + assert_fd_valid(fd.as_raw_fd()); + unsafe { libc::FD_ISSET(fd.as_raw_fd(), &self.set) } } /// Remove all file descriptors from this `FdSet`. @@ -77,8 +77,8 @@ impl<'fd> FdSet<'fd> { /// let fd_four = unsafe {BorrowedFd::borrow_raw(4)}; /// let fd_nine = unsafe {BorrowedFd::borrow_raw(9)}; /// let mut set = FdSet::new(); - /// set.insert(&fd_four); - /// set.insert(&fd_nine); + /// set.insert(fd_four); + /// set.insert(fd_nine); /// assert_eq!(set.highest().map(|borrowed_fd|borrowed_fd.as_raw_fd()), Some(9)); /// ``` /// @@ -101,8 +101,8 @@ impl<'fd> FdSet<'fd> { /// let mut set = FdSet::new(); /// let fd_four = unsafe {BorrowedFd::borrow_raw(4)}; /// let fd_nine = unsafe {BorrowedFd::borrow_raw(9)}; - /// set.insert(&fd_four); - /// set.insert(&fd_nine); + /// set.insert(fd_four); + /// set.insert(fd_nine); /// let fds: Vec<RawFd> = set.fds(None).map(|borrowed_fd|borrowed_fd.as_raw_fd()).collect(); /// assert_eq!(fds, vec![4, 9]); /// ``` @@ -134,7 +134,7 @@ impl<'a, 'fd> Iterator for Fds<'a, 'fd> { fn next(&mut self) -> Option<Self::Item> { for i in &mut self.range { let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) }; - if self.set.contains(&borrowed_i) { + if self.set.contains(borrowed_i) { return Some(borrowed_i); } } @@ -153,7 +153,7 @@ impl<'a, 'fd> DoubleEndedIterator for Fds<'a, 'fd> { fn next_back(&mut self) -> Option<BorrowedFd<'fd>> { while let Some(i) = self.range.next_back() { let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) }; - if self.set.contains(&borrowed_i) { + if self.set.contains(borrowed_i) { return Some(borrowed_i); } } @@ -317,238 +317,3 @@ where Errno::result(res) } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::sys::time::{TimeVal, TimeValLike}; - use crate::unistd::{close, pipe, write}; - use std::os::unix::io::{FromRawFd, OwnedFd, RawFd}; - - #[test] - fn fdset_insert() { - let mut fd_set = FdSet::new(); - - for i in 0..FD_SETSIZE { - let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) }; - assert!(!fd_set.contains(&borrowed_i)); - } - - let fd_seven = unsafe { BorrowedFd::borrow_raw(7) }; - fd_set.insert(&fd_seven); - - assert!(fd_set.contains(&fd_seven)); - } - - #[test] - fn fdset_remove() { - let mut fd_set = FdSet::new(); - - for i in 0..FD_SETSIZE { - let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) }; - assert!(!fd_set.contains(&borrowed_i)); - } - - let fd_seven = unsafe { BorrowedFd::borrow_raw(7) }; - fd_set.insert(&fd_seven); - fd_set.remove(&fd_seven); - - for i in 0..FD_SETSIZE { - let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) }; - assert!(!fd_set.contains(&borrowed_i)); - } - } - - #[test] - #[allow(non_snake_case)] - fn fdset_clear() { - let mut fd_set = FdSet::new(); - let fd_one = unsafe { BorrowedFd::borrow_raw(1) }; - let fd_FD_SETSIZE_devided_by_two = - unsafe { BorrowedFd::borrow_raw((FD_SETSIZE / 2) as RawFd) }; - let fd_FD_SETSIZE_minus_one = - unsafe { BorrowedFd::borrow_raw((FD_SETSIZE - 1) as RawFd) }; - fd_set.insert(&fd_one); - fd_set.insert(&fd_FD_SETSIZE_devided_by_two); - fd_set.insert(&fd_FD_SETSIZE_minus_one); - - fd_set.clear(); - - for i in 0..FD_SETSIZE { - let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) }; - assert!(!fd_set.contains(&borrowed_i)); - } - } - - #[test] - fn fdset_highest() { - let mut set = FdSet::new(); - assert_eq!( - set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()), - None - ); - let fd_zero = unsafe { BorrowedFd::borrow_raw(0) }; - let fd_ninety = unsafe { BorrowedFd::borrow_raw(90) }; - set.insert(&fd_zero); - assert_eq!( - set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()), - Some(0) - ); - set.insert(&fd_ninety); - assert_eq!( - set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()), - Some(90) - ); - set.remove(&fd_zero); - assert_eq!( - set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()), - Some(90) - ); - set.remove(&fd_ninety); - assert_eq!( - set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()), - None - ); - - let fd_four = unsafe { BorrowedFd::borrow_raw(4) }; - let fd_five = unsafe { BorrowedFd::borrow_raw(5) }; - let fd_seven = unsafe { BorrowedFd::borrow_raw(7) }; - set.insert(&fd_four); - set.insert(&fd_five); - set.insert(&fd_seven); - assert_eq!( - set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()), - Some(7) - ); - } - - #[test] - fn fdset_fds() { - let mut set = FdSet::new(); - let fd_zero = unsafe { BorrowedFd::borrow_raw(0) }; - let fd_ninety = unsafe { BorrowedFd::borrow_raw(90) }; - assert_eq!( - set.fds(None) - .map(|borrowed_fd| borrowed_fd.as_raw_fd()) - .collect::<Vec<_>>(), - vec![] - ); - set.insert(&fd_zero); - assert_eq!( - set.fds(None) - .map(|borrowed_fd| borrowed_fd.as_raw_fd()) - .collect::<Vec<_>>(), - vec![0] - ); - set.insert(&fd_ninety); - assert_eq!( - set.fds(None) - .map(|borrowed_fd| borrowed_fd.as_raw_fd()) - .collect::<Vec<_>>(), - vec![0, 90] - ); - - // highest limit - assert_eq!( - set.fds(Some(89)) - .map(|borrowed_fd| borrowed_fd.as_raw_fd()) - .collect::<Vec<_>>(), - vec![0] - ); - assert_eq!( - set.fds(Some(90)) - .map(|borrowed_fd| borrowed_fd.as_raw_fd()) - .collect::<Vec<_>>(), - vec![0, 90] - ); - } - - #[test] - fn test_select() { - let (r1, w1) = pipe().unwrap(); - let r1 = unsafe { OwnedFd::from_raw_fd(r1) }; - let w1 = unsafe { OwnedFd::from_raw_fd(w1) }; - let (r2, _w2) = pipe().unwrap(); - let r2 = unsafe { OwnedFd::from_raw_fd(r2) }; - - write(w1.as_raw_fd(), b"hi!").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)); - close(_w2).unwrap(); - } - - #[test] - fn test_select_nfds() { - let (r1, w1) = pipe().unwrap(); - let (r2, _w2) = pipe().unwrap(); - let r1 = unsafe { OwnedFd::from_raw_fd(r1) }; - let w1 = unsafe { OwnedFd::from_raw_fd(w1) }; - let r2 = unsafe { OwnedFd::from_raw_fd(r2) }; - - write(w1.as_raw_fd(), b"hi!").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() - .map(|borrowed_fd| borrowed_fd.as_raw_fd()) - .unwrap() - + 1 - ), - &mut fd_set, - None, - None, - &mut timeout - ) - .unwrap() - ); - } - assert!(fd_set.contains(&r1)); - assert!(!fd_set.contains(&r2)); - close(_w2).unwrap(); - } - - #[test] - fn test_select_nfds2() { - let (r1, w1) = pipe().unwrap(); - write(w1, b"hi!").unwrap(); - let (r2, _w2) = pipe().unwrap(); - let r1 = unsafe { OwnedFd::from_raw_fd(r1) }; - let r2 = unsafe { OwnedFd::from_raw_fd(r2) }; - 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.as_raw_fd(), r2.as_raw_fd()) + 1, - &mut fd_set, - None, - None, - &mut timeout - ) - .unwrap() - ); - assert!(fd_set.contains(&r1)); - assert!(!fd_set.contains(&r2)); - close(_w2).unwrap(); - } -} diff --git a/third_party/rust/nix/src/sys/sendfile.rs b/third_party/rust/nix/src/sys/sendfile.rs index 9f3c333f97..d7452edd7c 100644 --- a/third_party/rust/nix/src/sys/sendfile.rs +++ b/third_party/rust/nix/src/sys/sendfile.rs @@ -20,9 +20,9 @@ use crate::Result; /// /// `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())))] +/// For more information, see [the sendfile(2) man page.](https://man7.org/linux/man-pages/man2/sendfile.2.html) for Linux, +/// see [the sendfile(2) man page.](https://docs.oracle.com/cd/E88353_01/html/E37843/sendfile-3c.html) for Solaris. +#[cfg(any(linux_android, solarish))] pub fn sendfile<F1: AsFd, F2: AsFd>( out_fd: F1, in_fd: F2, @@ -56,7 +56,6 @@ pub fn sendfile<F1: AsFd, F2: AsFd>( /// /// 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<F1: AsFd, F2: AsFd>( out_fd: F1, in_fd: F2, @@ -78,46 +77,82 @@ pub fn sendfile64<F1: AsFd, F2: AsFd>( } cfg_if! { - if #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos"))] { + if #[cfg(any(freebsdlike, apple_targets))] { use std::io::IoSlice; #[derive(Clone, Debug)] - struct SendfileHeaderTrailer<'a>( - libc::sf_hdtr, - Option<Vec<IoSlice<'a>>>, - Option<Vec<IoSlice<'a>>>, - ); + struct SendfileHeaderTrailer<'a> { + raw: libc::sf_hdtr, + _headers: Option<Vec<IoSlice<'a>>>, + _trailers: 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<'_>>> = + let mut header_iovecs: Option<Vec<IoSlice<'_>>> = headers.map(|s| s.iter().map(|b| IoSlice::new(b)).collect()); - let trailer_iovecs: Option<Vec<IoSlice<'_>>> = + let mut trailer_iovecs: Option<Vec<IoSlice<'_>>> = trailers.map(|s| s.iter().map(|b| IoSlice::new(b)).collect()); - SendfileHeaderTrailer( - libc::sf_hdtr { + + SendfileHeaderTrailer { + raw: libc::sf_hdtr { headers: { header_iovecs - .as_ref() - .map_or(ptr::null(), |v| v.as_ptr()) as *mut libc::iovec + .as_mut() + .map_or(ptr::null_mut(), |v| v.as_mut_ptr()) + .cast() }, 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 + .as_mut() + .map_or(ptr::null_mut(), |v| v.as_mut_ptr()) + .cast() }, trl_cnt: trailer_iovecs.as_ref().map(|v| v.len()).unwrap_or(0) as i32 }, - header_iovecs, - trailer_iovecs, - ) + _headers: header_iovecs, + _trailers: trailer_iovecs, + } + } + } + } else if #[cfg(solarish)] { + use std::os::unix::io::BorrowedFd; + use std::marker::PhantomData; + + #[derive(Debug, Copy, Clone)] + /// Mapping of the raw C sendfilevec_t struct + pub struct SendfileVec<'fd> { + raw: libc::sendfilevec_t, + phantom: PhantomData<BorrowedFd<'fd>> + } + + impl<'fd> SendfileVec<'fd> { + /// initialises SendfileVec to send data directly from the process's address space + /// same in C with sfv_fd set to SFV_FD_SELF. + pub fn newself( + off: off_t, + len: usize + ) -> Self { + Self{raw: libc::sendfilevec_t{sfv_fd: libc::SFV_FD_SELF, sfv_flag: 0, sfv_off: off, sfv_len: len}, phantom: PhantomData} + } + + /// initialises SendfileVec to send data from `fd`. + pub fn new( + fd: BorrowedFd<'fd>, + off: off_t, + len: usize + ) -> SendfileVec<'fd> { + Self{raw: libc::sendfilevec_t{sfv_fd: fd.as_raw_fd(), sfv_flag: 0, sfv_off:off, sfv_len: len}, phantom: PhantomData} + } + } + + impl From<SendfileVec<'_>> for libc::sendfilevec_t { + fn from<'fd>(vec: SendfileVec) -> libc::sendfilevec_t { + vec.raw } } } @@ -187,7 +222,7 @@ cfg_if! { 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 hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.raw as *const libc::sf_hdtr); let return_code = unsafe { libc::sendfile(in_fd.as_fd().as_raw_fd(), out_sock.as_fd().as_raw_fd(), @@ -230,7 +265,7 @@ cfg_if! { ) -> (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 hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.raw as *const libc::sf_hdtr); let return_code = unsafe { libc::sendfile(in_fd.as_fd().as_raw_fd(), out_sock.as_fd().as_raw_fd(), @@ -242,7 +277,7 @@ cfg_if! { }; (Errno::result(return_code).and(Ok(())), bytes_sent) } - } else if #[cfg(any(target_os = "ios", target_os = "macos"))] { + } else if #[cfg(apple_targets)] { /// Read bytes from `in_fd` starting at `offset` and write up to `count` bytes to /// `out_sock`. /// @@ -276,7 +311,7 @@ cfg_if! { ) -> (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 hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.raw as *const libc::sf_hdtr); let return_code = unsafe { libc::sendfile(in_fd.as_fd().as_raw_fd(), out_sock.as_fd().as_raw_fd(), @@ -287,5 +322,30 @@ cfg_if! { }; (Errno::result(return_code).and(Ok(())), len) } + } else if #[cfg(solarish)] { + /// Write data from the vec arrays to `out_sock` and returns a `Result` and a + /// count of bytes written. + /// + /// Each `SendfileVec` set needs to be instantiated either with `SendfileVec::new` or + /// `SendfileVec::newself`. + /// + /// The former allows to send data from a file descriptor through `fd`, + /// from an offset `off` and for a given amount of data `len`. + /// + /// The latter allows to send data from the process's address space, from an offset `off` + /// and for a given amount of data `len`. + /// + /// For more information, see + /// [the sendfilev(3) man page.](https://illumos.org/man/3EXT/sendfilev) + pub fn sendfilev<F: AsFd>( + out_sock: F, + vec: &[SendfileVec] + ) -> (Result<()>, usize) { + let mut len = 0usize; + let return_code = unsafe { + libc::sendfilev(out_sock.as_fd().as_raw_fd(), vec.as_ptr() as *const libc::sendfilevec_t, vec.len() as i32, &mut len) + }; + (Errno::result(return_code).and(Ok(())), len) + } } } diff --git a/third_party/rust/nix/src/sys/signal.rs b/third_party/rust/nix/src/sys/signal.rs index c946e4a0b1..c9b593d0db 100644 --- a/third_party/rust/nix/src/sys/signal.rs +++ b/third_party/rust/nix/src/sys/signal.rs @@ -7,14 +7,17 @@ use crate::errno::Errno; use crate::{Error, Result}; use cfg_if::cfg_if; use std::fmt; +use std::hash::{Hash, Hasher}; use std::mem; -#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] +use std::ops::BitOr; +#[cfg(freebsdlike)] use std::os::unix::io::RawFd; use std::ptr; use std::str::FromStr; #[cfg(not(any( target_os = "fuchsia", + target_os = "hurd", target_os = "openbsd", target_os = "redox" )))] @@ -63,9 +66,12 @@ libc_enum! { /// 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", + #[cfg(all(any(linux_android, target_os = "emscripten", + target_os = "fuchsia"), + not(any(target_arch = "mips", + target_arch = "mips32r6", + target_arch = "mips64", + target_arch = "mips64r6", target_arch = "sparc64"))))] SIGSTKFLT, /// To parent on child stop or exit @@ -94,27 +100,21 @@ libc_enum! { 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", - target_os = "aix"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(linux_android, target_os = "emscripten", + target_os = "fuchsia", target_os = "aix"))] /// Power failure imminent. SIGPWR, /// Bad system call SIGSYS, - #[cfg(not(any(target_os = "android", target_os = "emscripten", - target_os = "fuchsia", target_os = "linux", + #[cfg(not(any(linux_android, target_os = "emscripten", + target_os = "fuchsia", 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", - target_os = "aix")))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(not(any(linux_android, target_os = "emscripten", + target_os = "fuchsia", target_os = "redox", + target_os = "haiku", target_os = "aix")))] /// Information request SIGINFO, } @@ -143,14 +143,15 @@ impl FromStr for Signal { "SIGTERM" => Signal::SIGTERM, #[cfg(all( any( - target_os = "android", + linux_android, target_os = "emscripten", target_os = "fuchsia", - target_os = "linux" ), not(any( target_arch = "mips", + target_arch = "mips32r6", target_arch = "mips64", + target_arch = "mips64r6", target_arch = "sparc64" )) ))] @@ -170,27 +171,24 @@ impl FromStr for Signal { #[cfg(not(target_os = "haiku"))] "SIGIO" => Signal::SIGIO, #[cfg(any( - target_os = "android", + linux_android, target_os = "emscripten", target_os = "fuchsia", - target_os = "linux" ))] "SIGPWR" => Signal::SIGPWR, "SIGSYS" => Signal::SIGSYS, #[cfg(not(any( - target_os = "android", + linux_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", + linux_android, target_os = "emscripten", target_os = "fuchsia", - target_os = "linux", target_os = "redox", target_os = "aix", target_os = "haiku" @@ -227,14 +225,15 @@ impl Signal { Signal::SIGTERM => "SIGTERM", #[cfg(all( any( - target_os = "android", + linux_android, target_os = "emscripten", target_os = "fuchsia", - target_os = "linux" ), not(any( target_arch = "mips", + target_arch = "mips32r6", target_arch = "mips64", + target_arch = "mips64r6", target_arch = "sparc64" )) ))] @@ -254,28 +253,25 @@ impl Signal { #[cfg(not(target_os = "haiku"))] Signal::SIGIO => "SIGIO", #[cfg(any( - target_os = "android", + linux_android, target_os = "emscripten", target_os = "fuchsia", target_os = "aix", - target_os = "linux" ))] Signal::SIGPWR => "SIGPWR", Signal::SIGSYS => "SIGSYS", #[cfg(not(any( - target_os = "android", + linux_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", + linux_android, target_os = "emscripten", target_os = "fuchsia", - target_os = "linux", target_os = "redox", target_os = "aix", target_os = "haiku" @@ -319,15 +315,12 @@ const SIGNALS: [Signal; 28] = [ SIGPROF, SIGWINCH, SIGSYS, ]; #[cfg(all( - any( - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia" - ), + any(linux_android, target_os = "emscripten", target_os = "fuchsia"), not(any( target_arch = "mips", + target_arch = "mips32r6", target_arch = "mips64", + target_arch = "mips64r6", target_arch = "sparc64" )) ))] @@ -339,13 +332,14 @@ const SIGNALS: [Signal; 31] = [ SIGVTALRM, SIGPROF, SIGWINCH, SIGIO, SIGPWR, SIGSYS, ]; #[cfg(all( + any(linux_android, target_os = "emscripten", target_os = "fuchsia"), any( - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia" - ), - any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64") + target_arch = "mips", + target_arch = "mips32r6", + target_arch = "mips64", + target_arch = "mips64r6", + target_arch = "sparc64" + ) ))] #[cfg(feature = "signal")] const SIGNALS: [Signal; 30] = [ @@ -363,8 +357,7 @@ const SIGNALS: [Signal; 30] = [ SIGVTALRM, SIGPROF, SIGXCPU, SIGXFSZ, SIGTRAP, ]; #[cfg(not(any( - target_os = "linux", - target_os = "android", + linux_android, target_os = "fuchsia", target_os = "emscripten", target_os = "aix", @@ -439,6 +432,7 @@ libc_bitflags! { SA_NOCLDSTOP; /// When catching a [`Signal::SIGCHLD`] signal, the system will not /// create zombie processes when children of the calling process exit. + #[cfg(not(target_os = "hurd"))] SA_NOCLDWAIT; /// Further occurrences of the delivered signal are not masked during /// the execution of the handler. @@ -486,7 +480,7 @@ use std::iter::IntoIterator; // 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)] +#[derive(Clone, Copy, Debug, Eq)] pub struct SigSet { sigset: libc::sigset_t } @@ -577,7 +571,6 @@ impl SigSet { /// 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; @@ -589,6 +582,35 @@ impl SigSet { }) } + /// Wait for a signal + /// + /// # Return value + /// If `sigsuspend(2)` is interrupted (EINTR), this function returns `Ok`. + /// If `sigsuspend(2)` set other error, this function returns `Err`. + /// + /// For more information see the + /// [`sigsuspend(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigsuspend.html). + #[cfg(any( + bsd, + linux_android, + solarish, + target_os = "haiku", + target_os = "hurd", + target_os = "aix", + target_os = "fushsia" + ))] + #[doc(alias("sigsuspend"))] + pub fn suspend(&self) -> Result<()> { + let res = unsafe { + libc::sigsuspend(&self.sigset as *const libc::sigset_t) + }; + match Errno::result(res).map(drop) { + Err(Errno::EINTR) => Ok(()), + Err(e) => Err(e), + Ok(_) => unreachable!("because this syscall always returns -1 if returns"), + } + } + /// Converts a `libc::sigset_t` object to a [`SigSet`] without checking whether the /// `libc::sigset_t` is already initialized. /// @@ -603,6 +625,42 @@ impl SigSet { } } +impl From<Signal> for SigSet { + fn from(signal: Signal) -> SigSet { + let mut sigset = SigSet::empty(); + sigset.add(signal); + sigset + } +} + +impl BitOr for Signal { + type Output = SigSet; + + fn bitor(self, rhs: Self) -> Self::Output { + let mut sigset = SigSet::empty(); + sigset.add(self); + sigset.add(rhs); + sigset + } +} + +impl BitOr<Signal> for SigSet { + type Output = SigSet; + + fn bitor(mut self, rhs: Signal) -> Self::Output { + self.add(rhs); + self + } +} + +impl BitOr for SigSet { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self::Output { + self.iter().chain(rhs.iter()).collect() + } +} + impl AsRef<libc::sigset_t> for SigSet { fn as_ref(&self) -> &libc::sigset_t { &self.sigset @@ -628,6 +686,27 @@ impl FromIterator<Signal> for SigSet { } } +impl PartialEq for SigSet { + fn eq(&self, other: &Self) -> bool { + for signal in Signal::iterator() { + if self.contains(signal) != other.contains(signal) { + return false; + } + } + true + } +} + +impl Hash for SigSet { + fn hash<H: Hasher>(&self, state: &mut H) { + for signal in Signal::iterator() { + if self.contains(signal) { + signal.hash(state); + } + } + } +} + /// Iterator for a [`SigSet`]. /// /// Call [`SigSet::iter`] to create an iterator. @@ -670,7 +749,6 @@ pub enum SigHandler { /// 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)) } @@ -689,23 +767,27 @@ impl SigAction { pub fn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction { #[cfg(not(target_os = "aix"))] 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, - }; + unsafe { + (*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, + }; + } } #[cfg(target_os = "aix")] unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) { - (*p).sa_union.__su_sigaction = match handler { - SigHandler::SigDfl => mem::transmute::<usize, extern "C" fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void)>(libc::SIG_DFL), - SigHandler::SigIgn => mem::transmute::<usize, extern "C" fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void)>(libc::SIG_IGN), - SigHandler::Handler(f) => mem::transmute::<extern "C" fn(i32), extern "C" fn(i32, *mut libc::siginfo_t, *mut libc::c_void)>(f), - SigHandler::SigAction(f) => f, - }; + unsafe { + (*p).sa_union.__su_sigaction = match handler { + SigHandler::SigDfl => unsafe { mem::transmute::<usize, extern "C" fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void)>(libc::SIG_DFL) }, + SigHandler::SigIgn => unsafe { mem::transmute::<usize, extern "C" fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void)>(libc::SIG_IGN) }, + SigHandler::Handler(f) => unsafe { mem::transmute::<extern "C" fn(i32), extern "C" fn(i32, *mut libc::siginfo_t, *mut libc::c_void)>(f) }, + SigHandler::SigAction(f) => f, + }; + } } let mut s = mem::MaybeUninit::<libc::sigaction>::uninit(); @@ -810,11 +892,11 @@ impl SigAction { 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, + let res = unsafe { libc::sigaction(signal as libc::c_int, &sigaction.sigaction as *const libc::sigaction, - oldact.as_mut_ptr()); + oldact.as_mut_ptr()) }; - Errno::result(res).map(|_| SigAction { sigaction: oldact.assume_init() }) + Errno::result(res).map(|_| SigAction { sigaction: unsafe { oldact.assume_init() } }) } /// Signal management (see [signal(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html)) @@ -872,9 +954,9 @@ pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigActi 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), + SigHandler::SigDfl => unsafe { libc::signal(signal, libc::SIG_DFL) }, + SigHandler::SigIgn => unsafe { libc::signal(signal, libc::SIG_IGN) }, + SigHandler::Handler(handler) => unsafe { libc::signal(signal, handler as libc::sighandler_t) }, #[cfg(not(target_os = "redox"))] SigHandler::SigAction(_) => return Err(Errno::ENOTSUP), }; @@ -883,9 +965,7 @@ pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result<SigHandler> 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)), + unsafe { *(&p as *const usize as *const extern fn(libc::c_int)) } as extern fn(libc::c_int)), } }) } @@ -1019,14 +1099,14 @@ feature! { #[cfg(target_os = "freebsd")] pub type type_of_thread_id = libc::lwpid_t; /// Identifies a thread for [`SigevNotify::SigevThreadId`] -#[cfg(any(target_env = "gnu", target_env = "uclibc"))] +#[cfg(all(not(target_os = "hurd"), any(target_env = "gnu", target_env = "uclibc")))] 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 = "fuchsia", target_os = "openbsd", target_os = "redox")))] +#[cfg(not(any(target_os = "fuchsia", target_os = "hurd", target_os = "openbsd", target_os = "redox")))] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum SigevNotify { /// No notification will be delivered @@ -1041,8 +1121,7 @@ pub enum SigevNotify { }, // Note: SIGEV_THREAD is not implemented, but could be if desired. /// Notify by delivering an event to a kqueue. - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] SigevKevent { /// File descriptor of the kqueue to notify. kq: RawFd, @@ -1051,7 +1130,6 @@ pub enum SigevNotify { }, /// Notify by delivering an event to a kqueue, with optional event flags set #[cfg(target_os = "freebsd")] - #[cfg_attr(docsrs, doc(cfg(all())))] #[cfg(feature = "event")] SigevKeventFlags { /// File descriptor of the kqueue to notify. @@ -1067,7 +1145,6 @@ pub enum SigevNotify { target_env = "gnu", target_env = "uclibc", ))] - #[cfg_attr(docsrs, doc(cfg(all())))] SigevThreadId { /// Signal to send signal: Signal, @@ -1082,10 +1159,10 @@ pub enum SigevNotify { #[cfg(not(any( target_os = "fuchsia", + target_os = "hurd", target_os = "openbsd", target_os = "redox" )))] -#[cfg_attr(docsrs, doc(cfg(all())))] mod sigevent { feature! { #![any(feature = "aio", feature = "signal")] @@ -1251,7 +1328,7 @@ mod sigevent { sev.sigev_signo = signal as libc::c_int; sev.sigev_value.sival_ptr = si_value as *mut libc::c_void }, - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg(freebsdlike)] SigevNotify::SigevKevent{kq, udata} => { sev.sigev_notify = libc::SIGEV_KEVENT; sev.sigev_signo = kq; @@ -1331,227 +1408,3 @@ mod 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/third_party/rust/nix/src/sys/signalfd.rs b/third_party/rust/nix/src/sys/signalfd.rs index 2b80ea643f..ccba774d1a 100644 --- a/third_party/rust/nix/src/sys/signalfd.rs +++ b/third_party/rust/nix/src/sys/signalfd.rs @@ -21,7 +21,7 @@ use crate::Result; pub use libc::signalfd_siginfo as siginfo; use std::mem; -use std::os::unix::io::{AsRawFd, RawFd, FromRawFd, OwnedFd, AsFd, BorrowedFd}; +use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd}; libc_bitflags! { pub struct SfdFlags: libc::c_int { @@ -45,18 +45,23 @@ pub const SIGNALFD_SIGINFO_SIZE: usize = mem::size_of::<siginfo>(); /// /// See [the signalfd man page for more information](https://man7.org/linux/man-pages/man2/signalfd.2.html) #[deprecated(since = "0.27.0", note = "Use SignalFd instead")] -pub fn signalfd<F: AsFd>(fd: Option<F>, mask: &SigSet, flags: SfdFlags) -> Result<OwnedFd> { +pub fn signalfd<F: AsFd>( + fd: Option<F>, + mask: &SigSet, + flags: SfdFlags, +) -> Result<OwnedFd> { _signalfd(fd, mask, flags) } -fn _signalfd<F: AsFd>(fd: Option<F>, mask: &SigSet, flags: SfdFlags) -> Result<OwnedFd> { - let raw_fd = fd.map_or(-1, |x|x.as_fd().as_raw_fd()); +fn _signalfd<F: AsFd>( + fd: Option<F>, + mask: &SigSet, + flags: SfdFlags, +) -> Result<OwnedFd> { + let raw_fd = fd.map_or(-1, |x| x.as_fd().as_raw_fd()); unsafe { - Errno::result(libc::signalfd( - raw_fd, - mask.as_ref(), - flags.bits(), - )).map(|raw_fd|FromRawFd::from_raw_fd(raw_fd)) + Errno::result(libc::signalfd(raw_fd, mask.as_ref(), flags.bits())) + .map(|raw_fd| FromRawFd::from_raw_fd(raw_fd)) } } @@ -101,7 +106,7 @@ impl SignalFd { } pub fn set_mask(&mut self, mask: &SigSet) -> Result<()> { - _signalfd(Some(self.0.as_fd()), mask, SfdFlags::empty()).map(drop) + self.update(mask, SfdFlags::empty()) } pub fn read_signal(&mut self) -> Result<Option<siginfo>> { @@ -109,7 +114,7 @@ impl SignalFd { let size = mem::size_of_val(&buffer); let res = Errno::result(unsafe { - libc::read(self.0.as_raw_fd(), buffer.as_mut_ptr() as *mut libc::c_void, size) + libc::read(self.0.as_raw_fd(), buffer.as_mut_ptr().cast(), size) }) .map(|r| r as usize); match res { @@ -119,6 +124,14 @@ impl SignalFd { Err(error) => Err(error), } } + + fn update(&self, mask: &SigSet, flags: SfdFlags) -> Result<()> { + let raw_fd = self.0.as_raw_fd(); + unsafe { + Errno::result(libc::signalfd(raw_fd, mask.as_ref(), flags.bits())) + .map(drop) + } + } } impl AsFd for SignalFd { @@ -142,34 +155,3 @@ impl Iterator for SignalFd { } } } - -#[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/third_party/rust/nix/src/sys/socket/addr.rs b/third_party/rust/nix/src/sys/socket/addr.rs index 1783531d49..f6800aa5d0 100644 --- a/third_party/rust/nix/src/sys/socket/addr.rs +++ b/third_party/rust/nix/src/sys/socket/addr.rs @@ -1,31 +1,22 @@ #[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", + bsd, + linux_android, + solarish, target_os = "haiku", target_os = "fuchsia", target_os = "aix", ))] #[cfg(feature = "net")] pub use self::datalink::LinkAddr; -#[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] +#[cfg(any(linux_android, apple_targets))] pub use self::vsock::VsockAddr; use super::sa_family_t; use crate::errno::Errno; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] use crate::sys::socket::addr::alg::AlgAddr; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] use crate::sys::socket::addr::netlink::NetlinkAddr; -#[cfg(all( - feature = "ioctl", - any(target_os = "ios", target_os = "macos") -))] +#[cfg(all(feature = "ioctl", apple_targets))] use crate::sys::socket::addr::sys_control::SysControlAddr; use crate::{NixPath, Result}; use cfg_if::cfg_if; @@ -33,6 +24,7 @@ use memoffset::offset_of; use std::convert::TryInto; use std::ffi::OsStr; use std::hash::{Hash, Hasher}; +use std::net::{Ipv4Addr, Ipv6Addr}; use std::os::unix::ffi::OsStrExt; use std::path::Path; use std::{fmt, mem, net, ptr, slice}; @@ -41,7 +33,7 @@ use std::{fmt, mem, net, ptr, slice}; #[cfg(feature = "net")] pub(crate) const fn ipv4addr_to_libc(addr: net::Ipv4Addr) -> libc::in_addr { libc::in_addr { - s_addr: u32::from_ne_bytes(addr.octets()) + s_addr: u32::from_ne_bytes(addr.octets()), } } @@ -49,7 +41,7 @@ pub(crate) const fn ipv4addr_to_libc(addr: net::Ipv4Addr) -> libc::in_addr { #[cfg(feature = "net")] pub(crate) const fn ipv6addr_to_libc(addr: &net::Ipv6Addr) -> libc::in6_addr { libc::in6_addr { - s6_addr: addr.octets() + s6_addr: addr.octets(), } } @@ -71,346 +63,188 @@ pub enum AddressFamily { /// 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())))] + #[cfg(linux_android)] Netlink = libc::AF_NETLINK, /// Kernel interface for interacting with the routing table - #[cfg(not(any( - target_os = "redox", - target_os = "linux", - target_os = "android" - )))] + #[cfg(not(any(linux_android, target_os = "redox")))] Route = libc::PF_ROUTE, /// 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())))] + #[cfg(any(linux_android, solarish, target_os = "fuchsia"))] Packet = libc::AF_PACKET, /// KEXT Controls and Notifications - #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(apple_targets)] System = libc::AF_SYSTEM, /// Amateur radio AX.25 protocol - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] Ax25 = libc::AF_AX25, /// IPX - Novell protocols #[cfg(not(any(target_os = "aix", target_os = "redox")))] - #[cfg_attr(docsrs, doc(cfg(all())))] Ipx = libc::AF_IPX, /// AppleTalk #[cfg(not(target_os = "redox"))] 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())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] Bridge = libc::AF_BRIDGE, /// Access to raw ATM PVCs - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] Rose = libc::AF_ROSE, /// DECet protocol sockets. #[cfg(not(any(target_os = "haiku", target_os = "redox")))] 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())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] Security = libc::AF_SECURITY, /// Key management protocol. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] Ash = libc::AF_ASH, /// Acorn Econet protocol - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] Econet = libc::AF_ECONET, /// Access to ATM Switched Virtual Circuits - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] AtmSvc = libc::AF_ATMSVC, /// Reliable Datagram Sockets (RDS) protocol - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] Rds = libc::AF_RDS, /// IBM SNA #[cfg(not(any(target_os = "haiku", target_os = "redox")))] Sna = libc::AF_SNA, /// Socket interface over IrDA - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] Can = libc::AF_CAN, /// TIPC, "cluster domain sockets" protocol - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] Tipc = libc::AF_TIPC, /// Bluetooth low-level socket protocol #[cfg(not(any( target_os = "aix", - target_os = "illumos", - target_os = "ios", - target_os = "macos", - target_os = "solaris", + solarish, + apple_targets, + target_os = "hurd", target_os = "redox", )))] - #[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())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] RxRpc = libc::AF_RXRPC, /// New "modular ISDN" driver interface protocol #[cfg(not(any( target_os = "aix", - target_os = "illumos", - target_os = "solaris", + solarish, target_os = "haiku", + target_os = "hurd", target_os = "redox", )))] - #[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())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] Caif = libc::AF_CAIF, /// Interface to kernel crypto API - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] 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", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(linux_android, apple_targets))] 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())))] + #[cfg(bsd)] 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())))] + #[cfg(bsd)] 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())))] + #[cfg(bsd)] 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())))] + #[cfg(any(apple_targets, netbsdlike))] 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())))] + #[cfg(bsd)] 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())))] + #[cfg(bsd)] 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())))] + #[cfg(bsd)] 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())))] + #[cfg(bsd)] 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())))] + #[cfg(bsd)] 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())))] + #[cfg(bsd)] 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())))] + #[cfg(any(bsd, solarish))] 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())))] + #[cfg(bsd)] 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())))] + #[cfg(bsd)] 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())))] + #[cfg(bsd)] 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())))] + #[cfg(linux_android)] Unspec = libc::AF_UNSPEC, } @@ -425,29 +259,17 @@ impl AddressFamily { 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"))] + #[cfg(linux_android)] libc::AF_NETLINK => Some(AddressFamily::Netlink), - #[cfg(any(target_os = "macos", target_os = "macos"))] + #[cfg(apple_targets)] libc::AF_SYSTEM => Some(AddressFamily::System), - #[cfg(not(any( - target_os = "redox", - target_os = "linux", - target_os = "android" - )))] + #[cfg(not(any(linux_android, target_os = "redox")))] libc::PF_ROUTE => Some(AddressFamily::Route), - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] 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" - ))] + #[cfg(any(bsd, solarish))] libc::AF_LINK => Some(AddressFamily::Link), - #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] + #[cfg(any(linux_android, apple_targets))] libc::AF_VSOCK => Some(AddressFamily::Vsock), _ => None, } @@ -463,13 +285,7 @@ pub struct UnixAddr { /// 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", - target_os = "redox", - ))] + #[cfg(not(any(bsd, target_os = "haiku", target_os = "hurd")))] sun_len: u8, } @@ -483,12 +299,12 @@ pub struct UnixAddr { enum UnixAddrKind<'a> { Pathname(&'a Path), Unnamed, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] Abstract(&'a [u8]), } impl<'a> UnixAddrKind<'a> { /// Safety: sun & sun_len must be valid - #[allow(clippy::unnecessary_cast)] // Not unnecessary on all platforms + #[allow(clippy::unnecessary_cast)] // Not unnecessary on all platforms 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 = @@ -496,16 +312,19 @@ impl<'a> UnixAddrKind<'a> { if path_len == 0 { return Self::Unnamed; } - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] 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, - ); + let name = unsafe { + slice::from_raw_parts( + sun.sun_path.as_ptr().add(1).cast(), + path_len - 1, + ) + }; return Self::Abstract(name); } - let pathname = - slice::from_raw_parts(sun.sun_path.as_ptr() as *const u8, path_len); + let pathname = unsafe { + slice::from_raw_parts(sun.sun_path.as_ptr().cast(), 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 @@ -525,7 +344,7 @@ impl<'a> UnixAddrKind<'a> { impl UnixAddr { /// Create a new sockaddr_un representing a filesystem path. - #[allow(clippy::unnecessary_cast)] // Not unnecessary on all platforms + #[allow(clippy::unnecessary_cast)] // Not unnecessary on all platforms pub fn new<P: ?Sized + NixPath>(path: &P) -> Result<UnixAddr> { path.with_nix_path(|cstr| unsafe { let mut ret = libc::sockaddr_un { @@ -544,20 +363,13 @@ impl UnixAddr { .try_into() .unwrap(); - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] + #[cfg(any(bsd, target_os = "haiku", target_os = "hurd"))] { ret.sun_len = sun_len; } ptr::copy_nonoverlapping( bytes.as_ptr(), - ret.sun_path.as_mut_ptr() as *mut u8, + ret.sun_path.as_mut_ptr().cast(), bytes.len(), ); @@ -571,9 +383,8 @@ impl UnixAddr { /// 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())))] - #[allow(clippy::unnecessary_cast)] // Not unnecessary on all platforms + #[cfg(linux_android)] + #[allow(clippy::unnecessary_cast)] // Not unnecessary on all platforms pub fn new_abstract(path: &[u8]) -> Result<UnixAddr> { unsafe { let mut ret = libc::sockaddr_un { @@ -593,7 +404,7 @@ impl UnixAddr { // 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, + ret.sun_path.as_mut_ptr().offset(1).cast(), path.len(), ); @@ -602,8 +413,7 @@ impl UnixAddr { } /// 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())))] + #[cfg(linux_android)] pub fn new_unnamed() -> UnixAddr { let ret = libc::sockaddr_un { sun_family: AddressFamily::Unix as sa_family_t, @@ -632,10 +442,9 @@ impl UnixAddr { sun_len: u8, ) -> UnixAddr { cfg_if! { - if #[cfg(any(target_os = "android", + if #[cfg(any(linux_android, target_os = "fuchsia", - target_os = "illumos", - target_os = "linux", + solarish, target_os = "redox", ))] { @@ -664,8 +473,7 @@ impl UnixAddr { /// /// 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())))] + #[cfg(linux_android)] pub fn as_abstract(&self) -> Option<&[u8]> { match self.kind() { UnixAddrKind::Abstract(name) => Some(name), @@ -674,8 +482,7 @@ impl UnixAddr { } /// Check if this address is an "unnamed" unix socket address. - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] #[inline] pub fn is_unnamed(&self) -> bool { matches!(self.kind(), UnixAddrKind::Unnamed) @@ -699,10 +506,9 @@ impl UnixAddr { fn sun_len(&self) -> u8 { cfg_if! { - if #[cfg(any(target_os = "android", + if #[cfg(any(linux_android, target_os = "fuchsia", - target_os = "illumos", - target_os = "linux", + solarish, target_os = "redox", ))] { @@ -717,10 +523,10 @@ impl UnixAddr { impl private::SockaddrLikePriv for UnixAddr {} impl SockaddrLike for UnixAddr { #[cfg(any( - target_os = "android", + linux_android, target_os = "fuchsia", - target_os = "illumos", - target_os = "linux" + solarish, + target_os = "redox" ))] fn len(&self) -> libc::socklen_t { self.sun_len.into() @@ -740,27 +546,26 @@ impl SockaddrLike for UnixAddr { return None; } } - if (*addr).sa_family as i32 != libc::AF_UNIX { + if unsafe { (*addr).sa_family as i32 != libc::AF_UNIX } { return None; } - let mut su: libc::sockaddr_un = mem::zeroed(); + let mut su: libc::sockaddr_un = unsafe { mem::zeroed() }; let sup = &mut su as *mut libc::sockaddr_un as *mut u8; cfg_if! { - if #[cfg(any(target_os = "android", + if #[cfg(any(linux_android, target_os = "fuchsia", - target_os = "illumos", - target_os = "linux", + solarish, target_os = "redox", ))] { 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); + let su_len = unsafe { 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)) + } + unsafe { ptr::copy(addr as *const u8, sup, su_len as usize) }; + Some(unsafe { Self::from_raw_parts(su, su_len as u8) }) } fn size() -> libc::socklen_t @@ -770,14 +575,16 @@ impl SockaddrLike for UnixAddr { mem::size_of::<libc::sockaddr_un>() as libc::socklen_t } - unsafe fn set_length(&mut self, new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> { + unsafe fn set_length( + &mut self, + new_length: usize, + ) -> std::result::Result<(), SocketAddressLengthNotDynamic> { // `new_length` is only used on some platforms, so it must be provided even when not used #![allow(unused_variables)] cfg_if! { - if #[cfg(any(target_os = "android", + if #[cfg(any(linux_android, target_os = "fuchsia", - target_os = "illumos", - target_os = "linux", + solarish, target_os = "redox", ))] { self.sun_len = new_length as u8; @@ -793,7 +600,7 @@ impl AsRef<libc::sockaddr_un> for UnixAddr { } } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] fn fmt_abstract(abs: &[u8], f: &mut fmt::Formatter) -> fmt::Result { use fmt::Write; f.write_str("@\"")?; @@ -810,7 +617,7 @@ impl fmt::Display for UnixAddr { 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"))] + #[cfg(linux_android)] UnixAddrKind::Abstract(name) => fmt_abstract(name, f), } } @@ -894,12 +701,7 @@ pub trait SockaddrLike: private::SockaddrLikePriv { } cfg_if! { - if #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] { + if #[cfg(bsd)] { /// Return the length of valid data in the sockaddr structure. /// /// For fixed-size sockaddrs, this should be the size of the @@ -946,7 +748,10 @@ pub trait SockaddrLike: private::SockaddrLikePriv { /// `new_length` must be a valid length for this type of address. Specifically, reads of that /// length from `self` must be valid. #[doc(hidden)] - unsafe fn set_length(&mut self, _new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> { + unsafe fn set_length( + &mut self, + _new_length: usize, + ) -> std::result::Result<(), SocketAddressLengthNotDynamic> { Err(SocketAddressLengthNotDynamic) } } @@ -1006,22 +811,20 @@ pub struct SockaddrIn(libc::sockaddr_in); 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) + pub const fn ip(&self) -> net::Ipv4Addr { + let bytes = self.0.sin_addr.s_addr.to_ne_bytes(); + let (a, b, c, d) = (bytes[0], bytes[1], bytes[2], bytes[3]); + Ipv4Addr::new(a, b, c, d) } /// 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", + bsd, target_os = "aix", target_os = "haiku", - target_os = "openbsd" + target_os = "hurd" ))] sin_len: Self::size() as u8, sin_family: AddressFamily::Inet as sa_family_t, @@ -1056,10 +859,10 @@ impl SockaddrLike for SockaddrIn { return None; } } - if (*addr).sa_family as i32 != libc::AF_INET { + if unsafe { (*addr).sa_family as i32 != libc::AF_INET } { return None; } - Some(Self(ptr::read_unaligned(addr as *const _))) + Some(Self(unsafe { ptr::read_unaligned(addr as *const _) })) } } @@ -1092,14 +895,10 @@ impl From<net::SocketAddrV4> for SockaddrIn { fn from(addr: net::SocketAddrV4) -> Self { Self(libc::sockaddr_in { #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", + bsd, target_os = "haiku", target_os = "hermit", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" + target_os = "hurd" ))] sin_len: mem::size_of::<libc::sockaddr_in>() as u8, sin_family: AddressFamily::Inet as sa_family_t, @@ -1143,8 +942,19 @@ impl SockaddrIn6 { } /// Returns the IP address associated with this socket address. - pub fn ip(&self) -> net::Ipv6Addr { - net::Ipv6Addr::from(self.0.sin6_addr.s6_addr) + pub const fn ip(&self) -> net::Ipv6Addr { + let bytes = self.0.sin6_addr.s6_addr; + let (a, b, c, d, e, f, g, h) = ( + ((bytes[0] as u16) << 8) | bytes[1] as u16, + ((bytes[2] as u16) << 8) | bytes[3] as u16, + ((bytes[4] as u16) << 8) | bytes[5] as u16, + ((bytes[6] as u16) << 8) | bytes[7] as u16, + ((bytes[8] as u16) << 8) | bytes[9] as u16, + ((bytes[10] as u16) << 8) | bytes[11] as u16, + ((bytes[12] as u16) << 8) | bytes[13] as u16, + ((bytes[14] as u16) << 8) | bytes[15] as u16, + ); + Ipv6Addr::new(a, b, c, d, e, f, g, h) } /// Returns the port number associated with this socket address, in native @@ -1175,10 +985,10 @@ impl SockaddrLike for SockaddrIn6 { return None; } } - if (*addr).sa_family as i32 != libc::AF_INET6 { + if unsafe { (*addr).sa_family as i32 != libc::AF_INET6 } { return None; } - Some(Self(ptr::read_unaligned(addr as *const _))) + Some(Self(unsafe { ptr::read_unaligned(addr as *const _) })) } } @@ -1210,14 +1020,10 @@ impl From<net::SocketAddrV6> for SockaddrIn6 { #[allow(clippy::needless_update)] // It isn't needless on Illumos Self(libc::sockaddr_in6 { #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", + bsd, target_os = "haiku", target_os = "hermit", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" + target_os = "hurd" ))] sin6_len: mem::size_of::<libc::sockaddr_in6>() as u8, sin6_family: AddressFamily::Inet6 as sa_family_t, @@ -1273,18 +1079,17 @@ impl std::str::FromStr for SockaddrIn6 { #[derive(Clone, Copy, Eq)] #[repr(C)] pub union SockaddrStorage { - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] alg: AlgAddr, - #[cfg(all(feature = "net", not(target_os = "redox")))] + #[cfg(all( + feature = "net", + not(any(target_os = "hurd", target_os = "redox")) + ))] #[cfg_attr(docsrs, doc(cfg(feature = "net")))] dl: LinkAddr, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] nl: NetlinkAddr, - #[cfg(all( - feature = "ioctl", - any(target_os = "ios", target_os = "macos") - ))] + #[cfg(all(feature = "ioctl", apple_targets))] #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))] sctl: SysControlAddr, #[cfg(feature = "net")] @@ -1293,8 +1098,7 @@ pub union SockaddrStorage { sin6: SockaddrIn6, ss: libc::sockaddr_storage, su: UnixAddr, - #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(linux_android, apple_targets))] vsock: VsockAddr, } impl private::SockaddrLikePriv for SockaddrStorage {} @@ -1316,21 +1120,22 @@ impl SockaddrLike for SockaddrStorage { { None } else { - let mut ss: libc::sockaddr_storage = mem::zeroed(); + let mut ss: libc::sockaddr_storage = unsafe { mem::zeroed() }; let ssp = &mut ss as *mut libc::sockaddr_storage as *mut u8; - ptr::copy(addr as *const u8, ssp, len as usize); + unsafe { ptr::copy(addr as *const u8, ssp, len as usize) }; #[cfg(any( - target_os = "android", + linux_android, target_os = "fuchsia", - target_os = "illumos", - target_os = "linux" + solarish, ))] 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; + unsafe { + (*(&mut ss as *mut libc::sockaddr_storage + as *mut UnixAddr)) + .sun_len = len as u8; + } } Some(Self { ss }) } @@ -1338,68 +1143,47 @@ impl SockaddrLike for SockaddrStorage { // 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 => { + match unsafe { (*addr).sa_family as i32 } { + #[cfg(linux_android)] + libc::AF_ALG => unsafe { AlgAddr::from_raw(addr, l).map(|alg| Self { alg }) - } + }, #[cfg(feature = "net")] - libc::AF_INET => { + libc::AF_INET => unsafe { SockaddrIn::from_raw(addr, l).map(|sin| Self { sin }) - } + }, #[cfg(feature = "net")] - libc::AF_INET6 => { + libc::AF_INET6 => unsafe { 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(any(bsd, solarish, target_os = "haiku"))] #[cfg(feature = "net")] - libc::AF_LINK => { + libc::AF_LINK => unsafe { LinkAddr::from_raw(addr, l).map(|dl| Self { dl }) - } - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_NETLINK => { + }, + #[cfg(linux_android)] + libc::AF_NETLINK => unsafe { NetlinkAddr::from_raw(addr, l).map(|nl| Self { nl }) - } - #[cfg(any( - target_os = "android", - target_os = "fuchsia", - target_os = "linux" - ))] + }, + #[cfg(any(linux_android, target_os = "fuchsia"))] #[cfg(feature = "net")] - libc::AF_PACKET => { + libc::AF_PACKET => unsafe { LinkAddr::from_raw(addr, l).map(|dl| Self { dl }) - } - #[cfg(all( - feature = "ioctl", - any(target_os = "ios", target_os = "macos") - ))] - libc::AF_SYSTEM => { + }, + #[cfg(all(feature = "ioctl", apple_targets))] + libc::AF_SYSTEM => unsafe { SysControlAddr::from_raw(addr, l).map(|sctl| Self { sctl }) - } - #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos" ))] - libc::AF_VSOCK => { + }, + #[cfg(any(linux_android, apple_targets))] + libc::AF_VSOCK => unsafe { VsockAddr::from_raw(addr, l).map(|vsock| Self { vsock }) - } + }, _ => None, } } } - #[cfg(any( - target_os = "android", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux" - ))] + #[cfg(any(linux_android, target_os = "fuchsia", solarish))] fn len(&self) -> libc::socklen_t { match self.as_unix_addr() { // The UnixAddr type knows its own length @@ -1409,11 +1193,12 @@ impl SockaddrLike for SockaddrStorage { } } - unsafe fn set_length(&mut self, new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> { + unsafe fn set_length( + &mut self, + new_length: usize, + ) -> std::result::Result<(), SocketAddressLengthNotDynamic> { match self.as_unix_addr_mut() { - Some(addr) => { - addr.set_length(new_length) - }, + Some(addr) => unsafe { addr.set_length(new_length) }, None => Err(SocketAddressLengthNotDynamic), } } @@ -1457,10 +1242,9 @@ impl SockaddrStorage { /// Downcast to an immutable `[UnixAddr]` reference. pub fn as_unix_addr(&self) -> Option<&UnixAddr> { cfg_if! { - if #[cfg(any(target_os = "android", + if #[cfg(any(linux_android, target_os = "fuchsia", - target_os = "illumos", - target_os = "linux" + solarish, ))] { let p = unsafe{ &self.ss as *const libc::sockaddr_storage }; @@ -1487,10 +1271,9 @@ impl SockaddrStorage { /// 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", + if #[cfg(any(linux_android, target_os = "fuchsia", - target_os = "illumos", - target_os = "linux" + solarish, ))] { let p = unsafe{ &self.ss as *const libc::sockaddr_storage }; @@ -1514,29 +1297,17 @@ impl SockaddrStorage { } } - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] 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(any(linux_android, target_os = "fuchsia"))] #[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(any(bsd, solarish))] #[cfg(feature = "net")] accessors! { as_link_addr, as_link_addr_mut, LinkAddr, @@ -1552,17 +1323,16 @@ impl SockaddrStorage { as_sockaddr_in6, as_sockaddr_in6_mut, SockaddrIn6, AddressFamily::Inet6, libc::sockaddr_in6, sin6} - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] 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(all(feature = "ioctl", apple_targets))] #[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", target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(linux_android, apple_targets))] accessors! {as_vsock_addr, as_vsock_addr_mut, VsockAddr, AddressFamily::Vsock, libc::sockaddr_vm, vsock} } @@ -1581,37 +1351,25 @@ 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"))] + #[cfg(linux_android)] 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(any(bsd, solarish))] #[cfg(feature = "net")] libc::AF_LINK => self.dl.fmt(f), - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] libc::AF_NETLINK => self.nl.fmt(f), - #[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, target_os = "fuchsia"))] #[cfg(feature = "net")] libc::AF_PACKET => self.dl.fmt(f), - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(apple_targets)] #[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", target_os = "macos"))] + #[cfg(any(linux_android, apple_targets))] libc::AF_VSOCK => self.vsock.fmt(f), _ => "<Address family unspecified>".fmt(f), } @@ -1655,37 +1413,25 @@ 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"))] + #[cfg(linux_android)] 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(any(bsd, solarish))] #[cfg(feature = "net")] libc::AF_LINK => self.dl.hash(s), - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] libc::AF_NETLINK => self.nl.hash(s), - #[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "fuchsia" - ))] + #[cfg(any(linux_android, target_os = "fuchsia"))] #[cfg(feature = "net")] libc::AF_PACKET => self.dl.hash(s), - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(apple_targets)] #[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", target_os = "macos"))] + #[cfg(any(linux_android, apple_targets))] libc::AF_VSOCK => self.vsock.hash(s), _ => self.ss.hash(s), } @@ -1697,37 +1443,25 @@ 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"))] + #[cfg(linux_android)] (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(any(bsd, solarish))] #[cfg(feature = "net")] (libc::AF_LINK, libc::AF_LINK) => self.dl == other.dl, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] (libc::AF_NETLINK, libc::AF_NETLINK) => self.nl == other.nl, - #[cfg(any( - target_os = "android", - target_os = "fuchsia", - target_os = "linux" - ))] + #[cfg(any(linux_android, target_os = "fuchsia"))] #[cfg(feature = "net")] (libc::AF_PACKET, libc::AF_PACKET) => self.dl == other.dl, - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(apple_targets)] #[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", target_os = "macos"))] + #[cfg(any(linux_android, apple_targets))] (libc::AF_VSOCK, libc::AF_VSOCK) => self.vsock == other.vsock, _ => false, } @@ -1751,8 +1485,7 @@ pub(super) mod private { } } -#[cfg(any(target_os = "android", target_os = "linux"))] -#[cfg_attr(docsrs, doc(cfg(all())))] +#[cfg(linux_android)] pub mod netlink { use super::*; use crate::sys::socket::addr::AddressFamily; @@ -1805,10 +1538,10 @@ pub mod netlink { return None; } } - if (*addr).sa_family as i32 != libc::AF_NETLINK { + if unsafe { (*addr).sa_family as i32 != libc::AF_NETLINK } { return None; } - Some(Self(ptr::read_unaligned(addr as *const _))) + Some(Self(unsafe { ptr::read_unaligned(addr as *const _) })) } } @@ -1825,11 +1558,10 @@ pub mod netlink { } } -#[cfg(any(target_os = "android", target_os = "linux"))] -#[cfg_attr(docsrs, doc(cfg(all())))] +#[cfg(linux_android)] pub mod alg { use super::*; - use libc::{c_char, sockaddr_alg, AF_ALG}; + use libc::{sockaddr_alg, AF_ALG}; use std::ffi::CStr; use std::hash::{Hash, Hasher}; use std::{fmt, mem, str}; @@ -1854,10 +1586,10 @@ pub mod alg { return None; } } - if (*addr).sa_family as i32 != libc::AF_ALG { + if unsafe { (*addr).sa_family as i32 != libc::AF_ALG } { return None; } - Some(Self(ptr::read_unaligned(addr as *const _))) + Some(Self(unsafe { ptr::read_unaligned(addr as *const _) })) } } @@ -1918,16 +1650,12 @@ pub mod alg { /// 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) - } + unsafe { CStr::from_ptr(self.0.salg_type.as_ptr().cast()) } } /// 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) - } + unsafe { CStr::from_ptr(self.0.salg_name.as_ptr().cast()) } } } @@ -1951,7 +1679,7 @@ pub mod alg { feature! { #![feature = "ioctl"] -#[cfg(any(target_os = "ios", target_os = "macos"))] +#[cfg(apple_targets)] pub mod sys_control { use crate::sys::socket::addr::AddressFamily; use libc::{self, c_uchar}; @@ -1994,10 +1722,10 @@ pub mod sys_control { return None; } } - if (*addr).sa_family as i32 != libc::AF_SYSTEM { + if unsafe { (*addr).sa_family as i32 != libc::AF_SYSTEM } { return None; } - Some(Self(ptr::read_unaligned(addr as *const _))) + Some(Self(unsafe { ptr::read_unaligned(addr as *const _) } )) } } @@ -2058,8 +1786,7 @@ pub mod sys_control { } } -#[cfg(any(target_os = "android", target_os = "linux", target_os = "fuchsia"))] -#[cfg_attr(docsrs, doc(cfg(all())))] +#[cfg(any(linux_android, target_os = "fuchsia"))] mod datalink { feature! { #![feature = "net"] @@ -2136,10 +1863,10 @@ mod datalink { return None; } } - if (*addr).sa_family as i32 != libc::AF_PACKET { + if unsafe { (*addr).sa_family as i32 != libc::AF_PACKET } { return None; } - Some(Self(ptr::read_unaligned(addr as *const _))) + Some(Self(unsafe { ptr::read_unaligned(addr as *const _) })) } } @@ -2152,18 +1879,7 @@ mod datalink { } } -#[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 = "aix", - target_os = "openbsd" -))] -#[cfg_attr(docsrs, doc(cfg(all())))] +#[cfg(any(bsd, solarish, target_os = "haiku", target_os = "aix"))] mod datalink { feature! { #![feature = "net"] @@ -2261,10 +1977,10 @@ mod datalink { return None; } } - if (*addr).sa_family as i32 != libc::AF_LINK { + if unsafe { (*addr).sa_family as i32 != libc::AF_LINK } { return None; } - Some(Self(ptr::read_unaligned(addr as *const _))) + Some(Self(unsafe { ptr::read_unaligned(addr as *const _) })) } } @@ -2276,8 +1992,7 @@ mod datalink { } } -#[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] -#[cfg_attr(docsrs, doc(cfg(all())))] +#[cfg(any(linux_android, apple_targets))] pub mod vsock { use super::*; use crate::sys::socket::addr::AddressFamily; @@ -2308,10 +2023,10 @@ pub mod vsock { return None; } } - if (*addr).sa_family as i32 != libc::AF_VSOCK { + if unsafe { (*addr).sa_family as i32 != libc::AF_VSOCK } { return None; } - Some(Self(ptr::read_unaligned(addr as *const _))) + unsafe { Some(Self(ptr::read_unaligned(addr as *const _))) } } } @@ -2322,32 +2037,47 @@ pub mod vsock { } impl PartialEq for VsockAddr { - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] 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) } - #[cfg(target_os = "macos")] + #[cfg(apple_targets)] fn eq(&self, other: &Self) -> bool { let (inner, other) = (self.0, other.0); - (inner.svm_family, inner.svm_cid, inner.svm_port, inner.svm_len) - == (other.svm_family, other.svm_cid, other.svm_port, inner.svm_len) + ( + inner.svm_family, + inner.svm_cid, + inner.svm_port, + inner.svm_len, + ) == ( + other.svm_family, + other.svm_cid, + other.svm_port, + inner.svm_len, + ) } } impl Eq for VsockAddr {} impl Hash for VsockAddr { - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] fn hash<H: Hasher>(&self, s: &mut H) { let inner = self.0; (inner.svm_family, inner.svm_cid, inner.svm_port).hash(s); } - #[cfg(target_os = "macos")] + #[cfg(apple_targets)] fn hash<H: Hasher>(&self, s: &mut H) { let inner = self.0; - (inner.svm_family, inner.svm_cid, inner.svm_port, inner.svm_len).hash(s); + ( + inner.svm_family, + inner.svm_cid, + inner.svm_port, + inner.svm_len, + ) + .hash(s); } } @@ -2363,9 +2093,9 @@ pub mod vsock { addr.svm_cid = cid; addr.svm_port = port; - #[cfg(target_os = "macos")] + #[cfg(apple_targets)] { - addr.svm_len = std::mem::size_of::<sockaddr_vm>() as u8; + addr.svm_len = std::mem::size_of::<sockaddr_vm>() as u8; } VsockAddr(addr) } @@ -2419,27 +2149,16 @@ mod tests { } } - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "hurd", target_os = "redox")))] mod link { #![allow(clippy::cast_ptr_alignment)] - #[cfg(any( - target_os = "ios", - target_os = "macos", - target_os = "illumos" - ))] + #[cfg(any(apple_targets, solarish))] 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" - ))] + #[cfg(bsd)] #[test] fn test_datalink_display() { use super::super::LinkAddr; @@ -2459,11 +2178,7 @@ mod tests { } #[cfg(all( - any( - target_os = "android", - target_os = "fuchsia", - target_os = "linux" - ), + any(linux_android, target_os = "fuchsia"), target_endian = "little" ))] #[test] @@ -2474,7 +2189,7 @@ mod tests { 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 sa = bytes.0.as_ptr().cast(); let len = None; let sock_addr = unsafe { SockaddrStorage::from_raw(sa, len) }.unwrap(); @@ -2485,12 +2200,12 @@ mod tests { } } - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(apple_targets)] #[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 sa = bytes.as_ptr().cast(); let len = Some(bytes.len() as socklen_t); let sock_addr = unsafe { SockaddrStorage::from_raw(sa, len) }.unwrap(); @@ -2503,7 +2218,7 @@ mod tests { } } - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(apple_targets)] #[test] fn macos_tap() { let bytes = [ @@ -2525,9 +2240,9 @@ mod tests { } } - #[cfg(target_os = "illumos")] + #[cfg(solarish)] #[test] - fn illumos_tap() { + fn solarish_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; @@ -2548,23 +2263,9 @@ mod tests { #[test] fn size() { - #[cfg(any( - target_os = "aix", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "illumos", - target_os = "openbsd", - target_os = "haiku" - ))] + #[cfg(any(bsd, target_os = "aix", solarish, target_os = "haiku"))] let l = mem::size_of::<libc::sockaddr_dl>(); - #[cfg(any( - target_os = "android", - target_os = "fuchsia", - target_os = "linux" - ))] + #[cfg(any(linux_android, target_os = "fuchsia"))] let l = mem::size_of::<libc::sockaddr_ll>(); assert_eq!(LinkAddr::size() as usize, l); } @@ -2588,6 +2289,13 @@ mod tests { SockaddrIn::size() as usize ); } + + #[test] + fn ip() { + let s = "127.0.0.1:8082"; + let ip = SockaddrIn::from_str(s).unwrap().ip(); + assert_eq!("127.0.0.1", format!("{ip}")); + } } mod sockaddr_in6 { @@ -2610,6 +2318,13 @@ mod tests { } #[test] + fn ip() { + let s = "[1234:5678:90ab:cdef::1111:2222]:8080"; + let ip = SockaddrIn6::from_str(s).unwrap().ip(); + assert_eq!("1234:5678:90ab:cdef::1111:2222", format!("{ip}")); + } + + #[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"; @@ -2628,28 +2343,28 @@ mod tests { #[test] fn from_sockaddr_un_named() { let ua = UnixAddr::new("/var/run/mysock").unwrap(); - let ptr = ua.as_ptr() as *const libc::sockaddr; + let ptr = ua.as_ptr().cast(); 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"))] + #[cfg(linux_android)] #[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 ptr = ua.as_ptr().cast(); 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"))] + #[cfg(linux_android)] #[test] fn from_sockaddr_un_abstract_unnamed() { let ua = UnixAddr::new_unnamed(); - let ptr = ua.as_ptr() as *const libc::sockaddr; + let ptr = ua.as_ptr().cast(); let ss = unsafe { SockaddrStorage::from_raw(ptr, Some(ua.len())) } .unwrap(); assert_eq!(ss.len(), ua.len()); @@ -2659,7 +2374,7 @@ mod tests { mod unixaddr { use super::*; - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] #[test] fn abstract_sun_path() { let name = String::from("nix\0abstract\0test"); diff --git a/third_party/rust/nix/src/sys/socket/mod.rs b/third_party/rust/nix/src/sys/socket/mod.rs index 78dd617c55..3d1651bd3f 100644 --- a/third_party/rust/nix/src/sys/socket/mod.rs +++ b/third_party/rust/nix/src/sys/socket/mod.rs @@ -1,7 +1,7 @@ //! Socket interface functions //! //! [Further reading](https://man7.org/linux/man-pages/man7/socket.7.html) -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(any(target_os = "freebsd", linux_android))] #[cfg(feature = "uio")] use crate::sys::time::TimeSpec; #[cfg(not(target_os = "redox"))] @@ -9,16 +9,16 @@ use crate::sys::time::TimeSpec; use crate::sys::time::TimeVal; use crate::{errno::Errno, Result}; use cfg_if::cfg_if; -use libc::{self, c_int, c_void, size_t, socklen_t}; +use libc::{self, c_int, size_t, socklen_t}; #[cfg(all(feature = "uio", not(target_os = "redox")))] use libc::{ - iovec, CMSG_DATA, CMSG_FIRSTHDR, CMSG_LEN, CMSG_NXTHDR, CMSG_SPACE, + c_void, iovec, CMSG_DATA, CMSG_FIRSTHDR, CMSG_LEN, CMSG_NXTHDR, CMSG_SPACE, }; #[cfg(not(target_os = "redox"))] use std::io::{IoSlice, IoSliceMut}; #[cfg(feature = "net")] use std::net; -use std::os::unix::io::{AsFd, AsRawFd, FromRawFd, RawFd, OwnedFd}; +use std::os::unix::io::{AsFd, AsRawFd, FromRawFd, OwnedFd, RawFd}; use std::{mem, ptr}; #[deny(missing_docs)] @@ -34,35 +34,25 @@ pub mod sockopt; pub use self::addr::{SockaddrLike, SockaddrStorage}; -#[cfg(any(target_os = "illumos", target_os = "solaris"))] +#[cfg(solarish)] pub use self::addr::{AddressFamily, UnixAddr}; -#[cfg(not(any(target_os = "illumos", target_os = "solaris")))] +#[cfg(not(solarish))] pub use self::addr::{AddressFamily, UnixAddr}; -#[cfg(not(any( - target_os = "illumos", - target_os = "solaris", - target_os = "haiku", - target_os = "redox", -)))] +#[cfg(not(any(solarish, target_os = "haiku", target_os = "hurd", target_os = "redox")))] #[cfg(feature = "net")] pub use self::addr::{LinkAddr, SockaddrIn, SockaddrIn6}; -#[cfg(any( - target_os = "illumos", - target_os = "solaris", - target_os = "haiku", - target_os = "redox", -))] +#[cfg(any(solarish, target_os = "haiku", target_os = "hurd", target_os = "redox"))] #[cfg(feature = "net")] pub use self::addr::{SockaddrIn, SockaddrIn6}; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] pub use crate::sys::socket::addr::alg::AlgAddr; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] pub use crate::sys::socket::addr::netlink::NetlinkAddr; -#[cfg(any(target_os = "ios", target_os = "macos"))] +#[cfg(apple_targets)] #[cfg(feature = "ioctl")] pub use crate::sys::socket::addr::sys_control::SysControlAddr; -#[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] +#[cfg(any(linux_android, apple_targets))] pub use crate::sys::socket::addr::vsock::VsockAddr; #[cfg(all(feature = "uio", not(target_os = "redox")))] @@ -132,121 +122,108 @@ pub enum SockProtocol { 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())))] + #[cfg(apple_targets)] 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())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] NetlinkSockDiag = libc::NETLINK_SOCK_DIAG, /// Netfilter/iptables ULOG. /// ([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())))] + #[cfg(linux_android)] NetlinkNFLOG = libc::NETLINK_NFLOG, /// 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())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] NetlinkKObjectUEvent = libc::NETLINK_KOBJECT_UEVENT, /// Generic netlink family for simplified netlink usage. /// ([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())))] + #[cfg(linux_android)] NetlinkGeneric = libc::NETLINK_GENERIC, /// 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())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] EthAll = (libc::ETH_P_ALL as u16).to_be() as i32, + /// ICMP protocol ([icmp(7)](https://man7.org/linux/man-pages/man7/icmp.7.html)) + Icmp = libc::IPPROTO_ICMP, + /// ICMPv6 protocol (ICMP over IPv6) + IcmpV6 = libc::IPPROTO_ICMPV6, +} + +impl SockProtocol { /// The Controller Area Network raw socket protocol /// ([ref](https://docs.kernel.org/networking/can.html#how-to-use-socketcan)) #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] - CanRaw = libc::CAN_RAW, -} + #[allow(non_upper_case_globals)] + pub const CanRaw: SockProtocol = SockProtocol::Icmp; // Matches libc::CAN_RAW -impl SockProtocol { /// The Controller Area Network broadcast manager protocol /// ([ref](https://docs.kernel.org/networking/can.html#how-to-use-socketcan)) #[cfg(target_os = "linux")] - #[cfg_attr(docsrs, doc(cfg(all())))] #[allow(non_upper_case_globals)] pub const CanBcm: SockProtocol = SockProtocol::NetlinkUserSock; // Matches libc::CAN_BCM + + /// 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(apple_targets)] + #[allow(non_upper_case_globals)] + pub const KextEvent: SockProtocol = SockProtocol::Icmp; // Matches libc::SYSPROTO_EVENT } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] libc_bitflags! { /// Configuration flags for `SO_TIMESTAMPING` interface /// @@ -276,33 +253,23 @@ 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())))] + #[cfg(any(linux_android, + freebsdlike, + netbsdlike, + solarish))] 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())))] + #[cfg(any(linux_android, + freebsdlike, + netbsdlike, + solarish))] 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; } } @@ -333,7 +300,6 @@ libc_bitflags! { /// the calling process and as well as other processes that hold /// file descriptors referring to the same open file description. #[cfg(not(target_os = "aix"))] - #[cfg_attr(docsrs, doc(cfg(all())))] MSG_DONTWAIT; /// Receive flags: Control Data was discarded (buffer too small) MSG_CTRUNC; @@ -352,8 +318,7 @@ libc_bitflags! { /// 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())))] + #[cfg(linux_android)] 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 @@ -362,44 +327,48 @@ libc_bitflags! { /// [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())))] + #[cfg(any(linux_android, freebsdlike, netbsdlike))] 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", + #[cfg(any(linux_android, + freebsdlike, + solarish, + netbsdlike, 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())))] + target_os = "haiku"))] MSG_NOSIGNAL; /// Turns on [`MSG_DONTWAIT`] after the first message has been received (only for /// `recvmmsg()`). - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, + netbsdlike, target_os = "fuchsia", - target_os = "linux", - target_os = "netbsd", - target_os = "freebsd", - target_os = "openbsd", - target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + target_os = "freebsd"))] MSG_WAITFORONE; } } +#[cfg(target_os = "freebsd")] +libc_enum! { + /// A selector for which clock to use when generating packet timestamps. + /// Used when setting [`TsClock`](crate::sys::socket::sockopt::TsClock) on a socket. + /// (For more details, see [setsockopt(2)](https://man.freebsd.org/cgi/man.cgi?setsockopt)). + #[repr(i32)] + #[non_exhaustive] + pub enum SocketTimestamp { + /// Microsecond resolution, realtime. This is the default. + SO_TS_REALTIME_MICRO, + /// Sub-nanosecond resolution, realtime. + SO_TS_BINTIME, + /// Nanosecond resolution, realtime. + SO_TS_REALTIME, + /// Nanosecond resolution, monotonic. + SO_TS_MONOTONIC, + } +} + cfg_if! { - if #[cfg(any(target_os = "android", target_os = "linux"))] { + if #[cfg(linux_android)] { /// Unix credentials of the sending process. /// /// This struct is used with the `SO_PEERCRED` ancillary message @@ -454,7 +423,7 @@ cfg_if! { uc.0 } } - } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] { + } else if #[cfg(freebsdlike)] { /// Unix credentials of the sending process. /// /// This struct is used with the `SCM_CREDS` ancillary message for UNIX sockets. @@ -487,7 +456,7 @@ cfg_if! { pub fn groups(&self) -> &[libc::gid_t] { unsafe { std::slice::from_raw_parts( - self.0.cmcred_groups.as_ptr() as *const libc::gid_t, + self.0.cmcred_groups.as_ptr(), self.0.cmcred_ngroups as _ ) } @@ -503,12 +472,7 @@ cfg_if! { } cfg_if! { - if #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "ios" - ))] { + if #[cfg(any(freebsdlike, apple_targets))] { /// Return type of [`LocalPeerCred`](crate::sys::socket::sockopt::LocalPeerCred) #[repr(transparent)] #[derive(Clone, Copy, Debug, Eq, PartialEq)] @@ -603,8 +567,6 @@ feature! { /// 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 ),* ) => { @@ -617,7 +579,7 @@ macro_rules! cmsg_space { #[inline] #[doc(hidden)] -pub fn cmsg_space<T>() -> usize { +pub const fn cmsg_space<T>() -> usize { // SAFETY: CMSG_SPACE is always safe unsafe { libc::CMSG_SPACE(mem::size_of::<T>() as libc::c_uint) as usize } } @@ -677,7 +639,7 @@ impl<'a> Iterator for CmsgIterator<'a> { } /// A type-safe wrapper around a single control message, as used with -/// [`recvmsg`](#fn.recvmsg). +/// [`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 @@ -692,12 +654,10 @@ 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())))] + #[cfg(linux_android)] ScmCredentials(UnixCredentials), /// Received version of [`ControlMessage::ScmCreds`] - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] ScmCreds(UnixCredentials), /// A message of type `SCM_TIMESTAMP`, containing the time the /// packet was received by the kernel. @@ -760,62 +720,44 @@ pub enum ControlMessageOwned { /// A set of nanosecond resolution timestamps /// /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] ScmTimestampsns(Timestamps), /// Nanoseconds resolution timestamp /// /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] ScmTimestampns(TimeSpec), - #[cfg(any( - target_os = "android", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - ))] + /// Realtime clock timestamp + /// + /// [Further reading](https://man.freebsd.org/cgi/man.cgi?setsockopt) + #[cfg(target_os = "freebsd")] + ScmRealtime(TimeSpec), + /// Monotonic clock timestamp + /// + /// [Further reading](https://man.freebsd.org/cgi/man.cgi?setsockopt) + #[cfg(target_os = "freebsd")] + ScmMonotonic(TimeSpec), + #[cfg(any(linux_android, apple_targets, 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(any(linux_android, bsd))] #[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(bsd)] #[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(bsd)] #[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(any(linux_android, target_os = "freebsd"))] #[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(any(linux_android, target_os = "freebsd"))] #[cfg(feature = "net")] #[cfg_attr(docsrs, doc(cfg(feature = "net")))] Ipv6OrigDstAddr(libc::sockaddr_in6), @@ -841,28 +783,31 @@ pub enum ControlMessageOwned { /// /// `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())))] + #[cfg(any(linux_android, target_os = "fuchsia"))] RxqOvfl(u32), /// Socket error queue control messages read with the `MSG_ERRQUEUE` flag. - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] #[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(linux_android)] #[cfg(feature = "net")] #[cfg_attr(docsrs, doc(cfg(feature = "net")))] Ipv6RecvErr(libc::sock_extended_err, Option<sockaddr_in6>), + /// `SOL_TLS` messages of type `TLS_GET_RECORD_TYPE` + #[cfg(any(target_os = "linux"))] + TlsGetRecordType(TlsGetRecordType), + /// Catch-all variant for unimplemented cmsg types. #[doc(hidden)] Unknown(UnknownCmsg), } /// For representing packet timestamps via `SO_TIMESTAMPING` interface -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub struct Timestamps { /// software based timestamp, usually one containing data @@ -873,6 +818,33 @@ pub struct Timestamps { pub hw_raw: TimeSpec, } +/// These constants correspond to TLS 1.2 message types, as defined in +/// RFC 5246, Appendix A.1 +#[cfg(any(target_os = "linux"))] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[repr(u8)] +#[non_exhaustive] +pub enum TlsGetRecordType { + ChangeCipherSpec , + Alert, + Handshake, + ApplicationData, + Unknown(u8), +} + +#[cfg(any(target_os = "linux"))] +impl From<u8> for TlsGetRecordType { + fn from(x: u8) -> Self { + match x { + 20 => TlsGetRecordType::ChangeCipherSpec, + 21 => TlsGetRecordType::Alert, + 22 => TlsGetRecordType::Handshake, + 23 => TlsGetRecordType::ApplicationData, + _ => TlsGetRecordType::Unknown(x), + } + } +} + impl ControlMessageOwned { /// Decodes a `ControlMessageOwned` from raw bytes. /// @@ -885,7 +857,7 @@ impl ControlMessageOwned { #[allow(clippy::cast_ptr_alignment)] unsafe fn decode_from(header: &cmsghdr) -> ControlMessageOwned { - let p = CMSG_DATA(header); + let p = unsafe { 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 @@ -895,158 +867,151 @@ impl ControlMessageOwned { 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)); + unsafe { + 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"))] + #[cfg(linux_android)] (libc::SOL_SOCKET, libc::SCM_CREDENTIALS) => { - let cred: libc::ucred = ptr::read_unaligned(p as *const _); + let cred: libc::ucred = unsafe { ptr::read_unaligned(p as *const _) }; ControlMessageOwned::ScmCredentials(cred.into()) } - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg(freebsdlike)] (libc::SOL_SOCKET, libc::SCM_CREDS) => { - let cred: libc::cmsgcred = ptr::read_unaligned(p as *const _); + let cred: libc::cmsgcred = unsafe { ptr::read_unaligned(p as *const _) }; ControlMessageOwned::ScmCreds(cred.into()) } #[cfg(not(any(target_os = "aix", target_os = "haiku")))] (libc::SOL_SOCKET, libc::SCM_TIMESTAMP) => { - let tv: libc::timeval = ptr::read_unaligned(p as *const _); + let tv: libc::timeval = unsafe { ptr::read_unaligned(p as *const _) }; ControlMessageOwned::ScmTimestamp(TimeVal::from(tv)) }, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] (libc::SOL_SOCKET, libc::SCM_TIMESTAMPNS) => { - let ts: libc::timespec = ptr::read_unaligned(p as *const _); + let ts: libc::timespec = unsafe { ptr::read_unaligned(p as *const _) }; ControlMessageOwned::ScmTimestampns(TimeSpec::from(ts)) } - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(target_os = "freebsd")] + (libc::SOL_SOCKET, libc::SCM_REALTIME) => { + let ts: libc::timespec = unsafe { ptr::read_unaligned(p as *const _) }; + ControlMessageOwned::ScmRealtime(TimeSpec::from(ts)) + } + #[cfg(target_os = "freebsd")] + (libc::SOL_SOCKET, libc::SCM_MONOTONIC) => { + let ts: libc::timespec = unsafe { ptr::read_unaligned(p as *const _) }; + ControlMessageOwned::ScmMonotonic(TimeSpec::from(ts)) + } + #[cfg(linux_android)] (libc::SOL_SOCKET, libc::SCM_TIMESTAMPING) => { let tp = p as *const libc::timespec; - let ts: libc::timespec = ptr::read_unaligned(tp); + let ts: libc::timespec = unsafe { ptr::read_unaligned(tp) }; let system = TimeSpec::from(ts); - let ts: libc::timespec = ptr::read_unaligned(tp.add(1)); + let ts: libc::timespec = unsafe { ptr::read_unaligned(tp.add(1)) }; let hw_trans = TimeSpec::from(ts); - let ts: libc::timespec = ptr::read_unaligned(tp.add(2)); + let ts: libc::timespec = unsafe { 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(any(target_os = "freebsd", linux_android, apple_targets))] #[cfg(feature = "net")] (libc::IPPROTO_IPV6, libc::IPV6_PKTINFO) => { - let info = ptr::read_unaligned(p as *const libc::in6_pktinfo); + let info = unsafe { 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(any(linux_android, apple_targets, target_os = "netbsd"))] #[cfg(feature = "net")] (libc::IPPROTO_IP, libc::IP_PKTINFO) => { - let info = ptr::read_unaligned(p as *const libc::in_pktinfo); + let info = unsafe { 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(bsd)] #[cfg(feature = "net")] (libc::IPPROTO_IP, libc::IP_RECVIF) => { - let dl = ptr::read_unaligned(p as *const libc::sockaddr_dl); + let dl = unsafe { 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(bsd)] #[cfg(feature = "net")] (libc::IPPROTO_IP, libc::IP_RECVDSTADDR) => { - let dl = ptr::read_unaligned(p as *const libc::in_addr); + let dl = unsafe { ptr::read_unaligned(p as *const libc::in_addr) }; ControlMessageOwned::Ipv4RecvDstAddr(dl) }, - #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] + #[cfg(any(linux_android, target_os = "freebsd"))] #[cfg(feature = "net")] (libc::IPPROTO_IP, libc::IP_ORIGDSTADDR) => { - let dl = ptr::read_unaligned(p as *const libc::sockaddr_in); + let dl = unsafe { 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 _); + let gso_size: u16 = unsafe { ptr::read_unaligned(p as *const _) }; ControlMessageOwned::UdpGroSegments(gso_size) }, - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + #[cfg(any(linux_android, target_os = "fuchsia"))] (libc::SOL_SOCKET, libc::SO_RXQ_OVFL) => { - let drop_counter = ptr::read_unaligned(p as *const u32); + let drop_counter = unsafe { ptr::read_unaligned(p as *const u32) }; ControlMessageOwned::RxqOvfl(drop_counter) }, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] #[cfg(feature = "net")] (libc::IPPROTO_IP, libc::IP_RECVERR) => { - let (err, addr) = Self::recv_err_helper::<sockaddr_in>(p, len); + let (err, addr) = unsafe { Self::recv_err_helper::<sockaddr_in>(p, len) }; ControlMessageOwned::Ipv4RecvErr(err, addr) }, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] #[cfg(feature = "net")] (libc::IPPROTO_IPV6, libc::IPV6_RECVERR) => { - let (err, addr) = Self::recv_err_helper::<sockaddr_in6>(p, len); + let (err, addr) = unsafe { Self::recv_err_helper::<sockaddr_in6>(p, len) }; ControlMessageOwned::Ipv6RecvErr(err, addr) }, - #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] + #[cfg(any(linux_android, target_os = "freebsd"))] #[cfg(feature = "net")] (libc::IPPROTO_IPV6, libc::IPV6_ORIGDSTADDR) => { - let dl = ptr::read_unaligned(p as *const libc::sockaddr_in6); + let dl = unsafe { ptr::read_unaligned(p as *const libc::sockaddr_in6) }; ControlMessageOwned::Ipv6OrigDstAddr(dl) }, + #[cfg(any(target_os = "linux"))] + (libc::SOL_TLS, libc::TLS_GET_RECORD_TYPE) => { + let content_type = unsafe { ptr::read_unaligned(p as *const u8) }; + ControlMessageOwned::TlsGetRecordType(content_type.into()) + }, (_, _) => { - let sl = std::slice::from_raw_parts(p, len); + let sl = unsafe { std::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(linux_android)] #[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); + let err = unsafe { 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; + let addrp = unsafe { libc::SO_EE_OFFENDER(ee) as *const T }; - if addrp.offset(1) as usize - (p as usize) > len { + if unsafe { addrp.offset(1) } as usize - (p as usize) > len { (err, None) } else { - (err, Some(ptr::read_unaligned(addrp))) + (err, Some(unsafe { 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. +/// A type-safe zero-copy wrapper around a single control message, as used with +/// [`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)] @@ -1074,8 +1039,7 @@ pub enum ControlMessage<'a> { /// /// 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())))] + #[cfg(linux_android)] ScmCredentials(&'a UnixCredentials), /// A message of type `SCM_CREDS`, containing the pid, uid, euid, gid and groups of /// a process connected to the socket. @@ -1089,41 +1053,28 @@ pub enum ControlMessage<'a> { /// /// 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())))] + #[cfg(freebsdlike)] 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())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] AlgSetAeadAssoclen(&'a u32), /// UDP GSO makes it possible for applications to generate network packets @@ -1139,51 +1090,52 @@ pub enum ControlMessage<'a> { #[cfg_attr(docsrs, doc(cfg(feature = "net")))] UdpGsoSegments(&'a u16), - /// Configure the sending addressing and interface for v4 + /// 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(any(linux_android, target_os = "netbsd", apple_targets))] #[cfg(feature = "net")] #[cfg_attr(docsrs, doc(cfg(feature = "net")))] Ipv4PacketInfo(&'a libc::in_pktinfo), - /// Configure the sending addressing and interface for v6 + /// 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", + #[cfg(any(linux_android, target_os = "netbsd", target_os = "freebsd", - target_os = "android", - target_os = "ios",))] + apple_targets))] #[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(any(freebsdlike, netbsdlike))] #[cfg(feature = "net")] #[cfg_attr(docsrs, doc(cfg(feature = "net")))] Ipv4SendSrcAddr(&'a libc::in_addr), + /// Configure the hop limit for v6 multicast traffic. + /// + /// Set the IPv6 hop limit for this message. The argument is an integer + /// between 0 and 255. A value of -1 will set the hop limit to the route + /// default if possible on the interface. Without this cmsg, packets sent + /// with sendmsg have a hop limit of 1 and will not leave the local network. + /// For further information, please refer to the + /// [`ipv6(7)`](https://man7.org/linux/man-pages/man7/ipv6.7.html) man page. + #[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "haiku"))] + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + Ipv6HopLimit(&'a libc::c_int), + /// 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())))] + #[cfg(any(linux_android, target_os = "fuchsia"))] RxqOvfl(&'a u32), /// Configure the transmission time of packets. @@ -1227,18 +1179,18 @@ impl<'a> ControlMessage<'a> { ControlMessage::ScmRights(fds) => { fds as *const _ as *const u8 }, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] ControlMessage::ScmCredentials(creds) => { &creds.0 as *const libc::ucred as *const u8 } - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg(freebsdlike)] 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"))] + #[cfg(linux_android)] ControlMessage::AlgSetIv(iv) => { #[allow(deprecated)] // https://github.com/rust-lang/libc/issues/1501 let af_alg_iv = libc::af_alg_iv { @@ -1263,11 +1215,11 @@ impl<'a> ControlMessage<'a> { return }, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] ControlMessage::AlgSetOp(op) => { op as *const _ as *const u8 }, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] ControlMessage::AlgSetAeadAssoclen(len) => { len as *const _ as *const u8 }, @@ -1276,21 +1228,20 @@ impl<'a> ControlMessage<'a> { 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(any(linux_android, target_os = "netbsd", apple_targets))] #[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(any(linux_android, target_os = "netbsd", + target_os = "freebsd", apple_targets))] #[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(any(freebsdlike, netbsdlike))] #[cfg(feature = "net")] ControlMessage::Ipv4SendSrcAddr(addr) => addr as *const _ as *const u8, - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + #[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "haiku"))] + #[cfg(feature = "net")] + ControlMessage::Ipv6HopLimit(limit) => limit as *const _ as *const u8, + #[cfg(any(linux_android, target_os = "fuchsia"))] ControlMessage::RxqOvfl(drop_count) => { drop_count as *const _ as *const u8 }, @@ -1314,23 +1265,23 @@ impl<'a> ControlMessage<'a> { ControlMessage::ScmRights(fds) => { mem::size_of_val(fds) }, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] ControlMessage::ScmCredentials(creds) => { mem::size_of_val(creds) } - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg(freebsdlike)] ControlMessage::ScmCreds => { mem::size_of::<libc::cmsgcred>() } - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] ControlMessage::AlgSetIv(iv) => { mem::size_of::<&[u8]>() + iv.len() }, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] ControlMessage::AlgSetOp(op) => { mem::size_of_val(op) }, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] ControlMessage::AlgSetAeadAssoclen(len) => { mem::size_of_val(len) }, @@ -1339,21 +1290,22 @@ impl<'a> ControlMessage<'a> { 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(any(linux_android, target_os = "netbsd", apple_targets))] #[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(any(linux_android, target_os = "netbsd", + target_os = "freebsd", apple_targets))] #[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(any(freebsdlike, netbsdlike))] #[cfg(feature = "net")] ControlMessage::Ipv4SendSrcAddr(addr) => mem::size_of_val(addr), - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + #[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "haiku"))] + #[cfg(feature = "net")] + ControlMessage::Ipv6HopLimit(limit) => { + mem::size_of_val(limit) + }, + #[cfg(any(linux_android, target_os = "fuchsia"))] ControlMessage::RxqOvfl(drop_count) => { mem::size_of_val(drop_count) }, @@ -1368,31 +1320,30 @@ impl<'a> ControlMessage<'a> { fn cmsg_level(&self) -> libc::c_int { match *self { ControlMessage::ScmRights(_) => libc::SOL_SOCKET, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] ControlMessage::ScmCredentials(_) => libc::SOL_SOCKET, - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg(freebsdlike)] ControlMessage::ScmCreds => libc::SOL_SOCKET, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] 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(any(linux_android, target_os = "netbsd", apple_targets))] #[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(any(linux_android, target_os = "netbsd", + target_os = "freebsd", apple_targets))] #[cfg(feature = "net")] ControlMessage::Ipv6PacketInfo(_) => libc::IPPROTO_IPV6, - #[cfg(any(target_os = "netbsd", target_os = "freebsd", - target_os = "openbsd", target_os = "dragonfly"))] + #[cfg(any(freebsdlike, netbsdlike))] #[cfg(feature = "net")] ControlMessage::Ipv4SendSrcAddr(_) => libc::IPPROTO_IP, - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + #[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "haiku"))] + #[cfg(feature = "net")] + ControlMessage::Ipv6HopLimit(_) => libc::IPPROTO_IPV6, + #[cfg(any(linux_android, target_os = "fuchsia"))] ControlMessage::RxqOvfl(_) => libc::SOL_SOCKET, #[cfg(target_os = "linux")] ControlMessage::TxTime(_) => libc::SOL_SOCKET, @@ -1403,19 +1354,19 @@ impl<'a> ControlMessage<'a> { fn cmsg_type(&self) -> libc::c_int { match *self { ControlMessage::ScmRights(_) => libc::SCM_RIGHTS, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] ControlMessage::ScmCredentials(_) => libc::SCM_CREDENTIALS, - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg(freebsdlike)] ControlMessage::ScmCreds => libc::SCM_CREDS, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] ControlMessage::AlgSetIv(_) => { libc::ALG_SET_IV }, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] ControlMessage::AlgSetOp(_) => { libc::ALG_SET_OP }, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] ControlMessage::AlgSetAeadAssoclen(_) => { libc::ALG_SET_AEAD_ASSOCLEN }, @@ -1424,21 +1375,20 @@ impl<'a> ControlMessage<'a> { ControlMessage::UdpGsoSegments(_) => { libc::UDP_SEGMENT }, - #[cfg(any(target_os = "linux", target_os = "macos", - target_os = "netbsd", target_os = "android", - target_os = "ios",))] + #[cfg(any(linux_android, target_os = "netbsd", apple_targets))] #[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(any(linux_android, target_os = "netbsd", + target_os = "freebsd", apple_targets))] #[cfg(feature = "net")] ControlMessage::Ipv6PacketInfo(_) => libc::IPV6_PKTINFO, - #[cfg(any(target_os = "netbsd", target_os = "freebsd", - target_os = "openbsd", target_os = "dragonfly"))] + #[cfg(any(freebsdlike, netbsdlike))] #[cfg(feature = "net")] ControlMessage::Ipv4SendSrcAddr(_) => libc::IP_SENDSRCADDR, - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + #[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "haiku"))] + #[cfg(feature = "net")] + ControlMessage::Ipv6HopLimit(_) => libc::IPV6_HOPLIMIT, + #[cfg(any(linux_android, target_os = "fuchsia"))] ControlMessage::RxqOvfl(_) => { libc::SO_RXQ_OVFL }, @@ -1452,10 +1402,12 @@ impl<'a> ControlMessage<'a> { // 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)); + unsafe { + (*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) ); + } } } @@ -1479,7 +1431,7 @@ impl<'a> ControlMessage<'a> { /// let (r, w) = pipe().unwrap(); /// /// let iov = [IoSlice::new(b"hello")]; -/// let fds = [r]; +/// let fds = [r.as_raw_fd()]; /// let cmsg = ControlMessage::ScmRights(&fds); /// sendmsg::<()>(fd1.as_raw_fd(), &iov, &[cmsg], MsgFlags::empty(), None).unwrap(); /// ``` @@ -1496,7 +1448,7 @@ impl<'a> ControlMessage<'a> { /// let (r, w) = pipe().unwrap(); /// /// let iov = [IoSlice::new(b"hello")]; -/// let fds = [r]; +/// let fds = [r.as_raw_fd()]; /// let cmsg = ControlMessage::ScmRights(&fds); /// sendmsg(fd.as_raw_fd(), &iov, &[cmsg], MsgFlags::empty(), Some(&localhost)).unwrap(); /// ``` @@ -1535,12 +1487,7 @@ pub fn sendmsg<S>(fd: RawFd, iov: &[IoSlice<'_>], cmsgs: &[ControlMessage], /// /// # References /// [`sendmsg`](fn.sendmsg.html) -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", -))] +#[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))] pub fn sendmmsg<'a, XS, AS, C, I, S>( fd: RawFd, data: &'a mut MultiHeaders<S>, @@ -1556,7 +1503,7 @@ pub fn sendmmsg<'a, XS, AS, C, I, S>( AS: AsRef<[Option<S>]>, I: AsRef<[IoSlice<'a>]> + 'a, C: AsRef<[ControlMessage<'a>]> + 'a, - S: SockaddrLike + 'a + S: SockaddrLike + 'a, { let mut count = 0; @@ -1564,11 +1511,11 @@ pub fn sendmmsg<'a, XS, AS, C, I, S>( for (i, ((slice, addr), mmsghdr)) in slices.into_iter().zip(addrs.as_ref()).zip(data.items.iter_mut() ).enumerate() { let p = &mut mmsghdr.msg_hdr; - p.msg_iov = slice.as_ref().as_ptr() as *mut libc::iovec; + p.msg_iov = slice.as_ref().as_ptr().cast_mut().cast(); 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 _; + p.msg_name = addr.as_ref().map_or(ptr::null(), S::as_ptr).cast_mut().cast(); // Encode each cmsg. This must happen after initializing the header because // CMSG_NEXT_HDR and friends read the msg_control and msg_controllen fields. @@ -1583,9 +1530,16 @@ pub fn sendmmsg<'a, XS, AS, C, I, S>( pmhdr = unsafe { CMSG_NXTHDR(p, pmhdr) }; } - count = i+1; + // Doing an unchecked addition is alright here, as the only way to obtain an instance of `MultiHeaders` + // is through the `preallocate` function, which takes an `usize` as an argument to define its size, + // which also provides an upper bound for the size of this zipped iterator. Thus, `i < usize::MAX` or in + // other words: `count` doesn't overflow + count = i + 1; } + // SAFETY: all pointers are guaranteed to be valid for the scope of this function. `count` does represent the + // maximum number of messages that can be sent safely (i.e. `count` is the minimum of the sizes of `slices`, + // `data.items` and `addrs`) let sent = Errno::result(unsafe { libc::sendmmsg( fd, @@ -1604,12 +1558,7 @@ pub fn sendmmsg<'a, XS, AS, C, I, S>( } -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", -))] +#[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))] #[derive(Debug)] /// Preallocated structures needed for [`recvmmsg`] and [`sendmmsg`] functions pub struct MultiHeaders<S> { @@ -1622,12 +1571,7 @@ pub struct MultiHeaders<S> { msg_controllen: usize, } -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", -))] +#[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))] impl<S> MultiHeaders<S> { /// Preallocate structure used by [`recvmmsg`] and [`sendmmsg`] takes number of headers to preallocate /// @@ -1652,7 +1596,7 @@ impl<S> MultiHeaders<S> { .enumerate() .map(|(ix, address)| { let (ptr, cap) = match &mut cmsg_buffers { - Some(v) => ((&mut v[ix * msg_controllen] as *mut u8), msg_controllen), + Some(v) => (&mut v[ix * msg_controllen] as *mut u8, msg_controllen), None => (std::ptr::null_mut(), 0), }; let msg_hdr = unsafe { pack_mhdr_to_receive(std::ptr::null_mut(), 0, ptr, cap, address.as_mut_ptr()) }; @@ -1697,12 +1641,7 @@ impl<S> MultiHeaders<S> { // 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", -))] +#[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))] pub fn recvmmsg<'a, XS, S, I>( fd: RawFd, data: &'a mut MultiHeaders<S>, @@ -1711,14 +1650,19 @@ pub fn recvmmsg<'a, XS, S, I>( mut timeout: Option<crate::sys::time::TimeSpec>, ) -> crate::Result<MultiResults<'a, S>> where - XS: IntoIterator<Item = &'a I>, - I: AsRef<[IoSliceMut<'a>]> + 'a, + XS: IntoIterator<Item = &'a mut I>, + I: AsMut<[IoSliceMut<'a>]> + 'a, { let mut count = 0; for (i, (slice, mmsghdr)) in slices.into_iter().zip(data.items.iter_mut()).enumerate() { let 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_iov = slice.as_mut().as_mut_ptr().cast(); + p.msg_iovlen = slice.as_mut().len() as _; + + // Doing an unchecked addition is alright here, as the only way to obtain an instance of `MultiHeaders` + // is through the `preallocate` function, which takes an `usize` as an argument to define its size, + // which also provides an upper bound for the size of this zipped iterator. Thus, `i < usize::MAX` or in + // other words: `count` doesn't overflow count = i + 1; } @@ -1726,6 +1670,8 @@ where .as_mut() .map_or_else(std::ptr::null_mut, |t| t as *mut _ as *mut libc::timespec); + // SAFETY: all pointers are guaranteed to be valid for the scope of this function. `count` does represent the + // maximum number of messages that can be received safely (i.e. `count` is the minimum of the sizes of `slices` and `data.items`) let received = Errno::result(unsafe { libc::recvmmsg( fd, @@ -1743,16 +1689,9 @@ where }) } -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", -))] -#[derive(Debug)] /// Iterator over results of [`recvmmsg`]/[`sendmmsg`] -/// -/// +#[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))] +#[derive(Debug)] pub struct MultiResults<'a, S> { // preallocated structures rmm: &'a MultiHeaders<S>, @@ -1760,12 +1699,7 @@ pub struct MultiResults<'a, S> { received: usize, } -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", -))] +#[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))] impl<'a, S> Iterator for MultiResults<'a, S> where S: Copy + SockaddrLike, @@ -1838,108 +1772,6 @@ impl<'a> Iterator for IoSliceIterator<'a> { } } -// 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; - use std::os::unix::io::AsRawFd; - - #[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.as_raw_fd(), &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.as_raw_fd(), &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.as_raw_fd(), &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, @@ -1951,19 +1783,23 @@ unsafe fn read_mhdr<'a, 'i, S>( // The cast is not unnecessary on all platforms. #[allow(clippy::unnecessary_cast)] let cmsghdr = { - if mhdr.msg_controllen > 0 { + let ptr = 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) + unsafe { CMSG_FIRSTHDR(&mhdr as *const msghdr) } } else { ptr::null() - }.as_ref() + }; + + unsafe { + ptr.as_ref() + } }; // Ignore errors if this socket address has statically-known length // // This is to ensure that unix socket addresses have their length set appropriately. - let _ = address.set_length(mhdr.msg_namelen as usize); + let _ = unsafe { address.set_length(mhdr.msg_namelen as usize) }; RecvMsg { bytes: r as usize, @@ -2000,14 +1836,16 @@ unsafe fn pack_mhdr_to_receive<S>( // initialize it. let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed(); let p = mhdr.as_mut_ptr(); - (*p).msg_name = address 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() + unsafe { + (*p).msg_name = address 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>( @@ -2025,7 +1863,7 @@ fn pack_mhdr_to_send<'a, I, C, S>( // The message header must be initialized before the individual cmsgs. let cmsg_ptr = if capacity > 0 { - cmsg_buffer.as_mut_ptr() as *mut c_void + cmsg_buffer.as_mut_ptr().cast() } else { ptr::null_mut() }; @@ -2035,11 +1873,11 @@ fn pack_mhdr_to_send<'a, I, C, S>( // 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_name = addr.map(S::as_ptr).unwrap_or(ptr::null()).cast_mut().cast(); (*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_iov = iov.as_ref().as_ptr().cast_mut().cast(); (*p).msg_iovlen = iov.as_ref().len() as _; (*p).msg_control = cmsg_ptr; (*p).msg_controllen = capacity as _; @@ -2166,17 +2004,51 @@ pub fn socketpair<T: Into<Option<SockProtocol>>>( Errno::result(res)?; // Safe because socketpair returned success. - unsafe { - Ok((OwnedFd::from_raw_fd(fds[0]), OwnedFd::from_raw_fd(fds[1]))) + unsafe { Ok((OwnedFd::from_raw_fd(fds[0]), OwnedFd::from_raw_fd(fds[1]))) } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Backlog(i32); + +impl Backlog { + /// Sets the listen queue size to system `SOMAXCONN` value + pub const MAXCONN: Self = Self(libc::SOMAXCONN); + /// Sets the listen queue size to -1 for system supporting it + #[cfg(any(target_os = "linux", target_os = "freebsd"))] + pub const MAXALLOWABLE: Self = Self(-1); + + /// Create a `Backlog`, an `EINVAL` will be returned if `val` is invalid. + pub fn new<I: Into<i32>>(val: I) -> Result<Self> { + cfg_if! { + if #[cfg(any(target_os = "linux", target_os = "freebsd"))] { + const MIN: i32 = -1; + } else { + const MIN: i32 = 0; + } + } + + let val = val.into(); + + if !(MIN..Self::MAXCONN.0).contains(&val) { + return Err(Errno::EINVAL); + } + + Ok(Self(val)) + } +} + +impl From<Backlog> for i32 { + fn from(backlog: Backlog) -> Self { + backlog.0 } } /// Listen for connections on a socket /// /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html) -pub fn listen<F: AsFd>(sock: &F, backlog: usize) -> Result<()> { +pub fn listen<F: AsFd>(sock: &F, backlog: Backlog) -> Result<()> { let fd = sock.as_fd().as_raw_fd(); - let res = unsafe { libc::listen(fd, backlog as c_int) }; + let res = unsafe { libc::listen(fd, backlog.into()) }; Errno::result(res).map(drop) } @@ -2211,14 +2083,12 @@ pub fn accept(sockfd: RawFd) -> Result<RawFd> { target_arch = "x86_64" ) ), - target_os = "dragonfly", + freebsdlike, + netbsdlike, target_os = "emscripten", - target_os = "freebsd", target_os = "fuchsia", - target_os = "illumos", + solarish, target_os = "linux", - target_os = "netbsd", - target_os = "openbsd" ))] pub fn accept4(sockfd: RawFd, flags: SockFlag) -> Result<RawFd> { let res = unsafe { @@ -2245,7 +2115,7 @@ pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result<usize> { unsafe { let ret = libc::recv( sockfd, - buf.as_mut_ptr() as *mut c_void, + buf.as_mut_ptr().cast(), buf.len() as size_t, flags.bits(), ); @@ -2269,20 +2139,14 @@ pub fn recvfrom<T: SockaddrLike>( let ret = Errno::result(libc::recvfrom( sockfd, - buf.as_mut_ptr() as *mut c_void, + buf.as_mut_ptr().cast(), buf.len() as size_t, 0, - addr.as_mut_ptr() as *mut sockaddr, + addr.as_mut_ptr().cast(), &mut len as *mut socklen_t, ))? as usize; - Ok(( - ret, - T::from_raw( - addr.assume_init().as_ptr(), - Some(len), - ), - )) + Ok((ret, T::from_raw(addr.assume_init().as_ptr(), Some(len)))) } } @@ -2298,7 +2162,7 @@ pub fn sendto( let ret = unsafe { libc::sendto( fd, - buf.as_ptr() as *const c_void, + buf.as_ptr().cast(), buf.len() as size_t, flags.bits(), addr.as_ptr(), @@ -2314,12 +2178,7 @@ pub fn sendto( /// [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(), - ) + libc::send(fd, buf.as_ptr().cast(), buf.len() as size_t, flags.bits()) }; Errno::result(ret).map(|r| r as usize) @@ -2386,8 +2245,7 @@ pub fn getpeername<T: SockaddrLike>(fd: RawFd) -> Result<T> { let mut addr = mem::MaybeUninit::<T>::uninit(); let mut len = T::size(); - let ret = - libc::getpeername(fd, addr.as_mut_ptr() as *mut sockaddr, &mut len); + let ret = libc::getpeername(fd, addr.as_mut_ptr().cast(), &mut len); Errno::result(ret)?; @@ -2403,8 +2261,7 @@ pub fn getsockname<T: SockaddrLike>(fd: RawFd) -> Result<T> { let mut addr = mem::MaybeUninit::<T>::uninit(); let mut len = T::size(); - let ret = - libc::getsockname(fd, addr.as_mut_ptr() as *mut sockaddr, &mut len); + let ret = libc::getsockname(fd, addr.as_mut_ptr().cast(), &mut len); Errno::result(ret)?; @@ -2439,27 +2296,3 @@ pub fn shutdown(df: RawFd, how: Shutdown) -> Result<()> { } } -#[cfg(test)] -mod tests { - #[cfg(not(target_os = "redox"))] - #[test] - fn can_use_cmsg_space() { - let _ = cmsg_space!(u8); - } - - #[cfg(not(any( - target_os = "redox", - target_os = "linux", - target_os = "android" - )))] - #[test] - fn can_open_routing_socket() { - let _ = super::socket( - super::AddressFamily::Route, - super::SockType::Raw, - super::SockFlag::empty(), - None, - ) - .expect("Failed to open routing socket"); - } -} diff --git a/third_party/rust/nix/src/sys/socket/sockopt.rs b/third_party/rust/nix/src/sys/socket/sockopt.rs index 44f3ebbc1d..4357695f56 100644 --- a/third_party/rust/nix/src/sys/socket/sockopt.rs +++ b/third_party/rust/nix/src/sys/socket/sockopt.rs @@ -7,7 +7,6 @@ use cfg_if::cfg_if; use libc::{self, c_int, c_void, socklen_t}; use std::ffi::{OsStr, OsString}; use std::mem::{self, MaybeUninit}; -#[cfg(target_family = "unix")] use std::os::unix::ffi::OsStrExt; use std::os::unix::io::{AsFd, AsRawFd}; @@ -128,7 +127,7 @@ macro_rules! getsockopt_impl { /// 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`), +/// (`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 `getsockopt`/`setsockopt` call. /// * `$flag:path`: a flag name to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`, @@ -261,7 +260,7 @@ sockopt_impl!( libc::SO_REUSEADDR, bool ); -#[cfg(not(any(target_os = "illumos", target_os = "solaris")))] +#[cfg(not(solarish))] sockopt_impl!( /// Permits multiple AF_INET or AF_INET6 sockets to be bound to an /// identical socket address. @@ -318,7 +317,7 @@ sockopt_impl!( super::IpMembershipRequest ); cfg_if! { - if #[cfg(any(target_os = "android", target_os = "linux"))] { + if #[cfg(linux_android)] { #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -329,14 +328,7 @@ cfg_if! { #[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"))] { + } else if #[cfg(any(bsd, solarish))] { #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -365,6 +357,17 @@ sockopt_impl!( #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// Set or read the hop limit value of outgoing IPv6 multicast packets for + /// this socket. + Ipv6MulticastHops, + Both, + libc::IPPROTO_IPV6, + libc::IPV6_MULTICAST_HOPS, + libc::c_int +); +#[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, @@ -408,7 +411,7 @@ sockopt_impl!( libc::IPV6_TCLASS, libc::c_int ); -#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] +#[cfg(any(linux_android, target_os = "fuchsia"))] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -420,6 +423,20 @@ sockopt_impl!( libc::IP_FREEBIND, bool ); +#[cfg(linux_android)] +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// If enabled, the kernel will not reserve an ephemeral port when binding + /// socket with a port number of 0. The port will later be automatically + /// chosen at connect time, in a way that allows sharing a source port as + /// long as the 4-tuple is unique. + IpBindAddressNoPort, + Both, + libc::IPPROTO_IP, + libc::IP_BIND_ADDRESS_NO_PORT, + bool +); sockopt_impl!( /// Specify the receiving timeout until reporting an error. ReceiveTimeout, @@ -477,12 +494,7 @@ sockopt_impl!( libc::SO_KEEPALIVE, bool ); -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "ios" -))] +#[cfg(any(freebsdlike, apple_targets))] sockopt_impl!( /// Get the credentials of the peer process of a connected unix domain /// socket. @@ -492,7 +504,7 @@ sockopt_impl!( libc::LOCAL_PEERCRED, super::XuCred ); -#[cfg(any(target_os = "macos", target_os = "ios"))] +#[cfg(apple_targets)] sockopt_impl!( /// Get the PID of the peer process of a connected unix domain socket. LocalPeerPid, @@ -501,7 +513,7 @@ sockopt_impl!( libc::LOCAL_PEERPID, libc::c_int ); -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] sockopt_impl!( /// Return the credentials of the foreign process connected to this socket. PeerCredentials, @@ -510,7 +522,18 @@ sockopt_impl!( libc::SO_PEERCRED, super::UnixCredentials ); -#[cfg(any(target_os = "ios", target_os = "macos"))] +#[cfg(target_os = "freebsd")] +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// Get backlog limit of the socket + ListenQLimit, + GetOnly, + libc::SOL_SOCKET, + libc::SO_LISTENQLIMIT, + u32 +); +#[cfg(apple_targets)] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -522,12 +545,7 @@ sockopt_impl!( libc::TCP_KEEPALIVE, u32 ); -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux" -))] +#[cfg(any(freebsdlike, linux_android))] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -540,7 +558,7 @@ sockopt_impl!( u32 ); cfg_if! { - if #[cfg(any(target_os = "android", target_os = "linux"))] { + if #[cfg(linux_android)] { sockopt_impl!( /// The maximum segment size for outgoing TCP packets. TcpMaxSeg, Both, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32); @@ -550,7 +568,11 @@ cfg_if! { TcpMaxSeg, GetOnly, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32); } } -#[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "redox")))] +#[cfg(not(any( + target_os = "openbsd", + target_os = "haiku", + target_os = "redox" +)))] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -562,7 +584,7 @@ sockopt_impl!( libc::TCP_KEEPCNT, u32 ); -#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] +#[cfg(any(linux_android, target_os = "fuchsia"))] sockopt_impl!( #[allow(missing_docs)] // Not documented by Linux! @@ -572,7 +594,11 @@ sockopt_impl!( libc::TCP_REPAIR, u32 ); -#[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "redox")))] +#[cfg(not(any( + target_os = "openbsd", + target_os = "haiku", + target_os = "redox" +)))] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -596,6 +622,26 @@ sockopt_impl!( libc::TCP_USER_TIMEOUT, u32 ); +#[cfg(linux_android)] +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// Enables TCP Fast Open (RFC 7413) on a connecting socket. If a fast open + /// cookie is not available (first attempt to connect), `connect` syscall + /// will behave as usual, except for internally trying to solicit a cookie + /// from remote peer. When cookie is available, the next `connect` syscall + /// will immediately succeed without actually establishing TCP connection. + /// The connection establishment will be defered till the next `write` or + /// `sendmsg` syscalls on the socket, allowing TCP prtocol to establish + /// connection and send data in the same packets. Note: calling `read` right + /// after `connect` without `write` on the socket will cause the blocking + /// socket to be blocked forever. + TcpFastOpenConnect, + Both, + libc::IPPROTO_TCP, + libc::TCP_FASTOPEN_CONNECT, + bool +); sockopt_impl!( /// Sets or gets the maximum socket receive buffer in bytes. RcvBuf, @@ -612,7 +658,7 @@ sockopt_impl!( libc::SO_SNDBUF, usize ); -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] 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 @@ -623,7 +669,7 @@ sockopt_impl!( libc::SO_RCVBUFFORCE, usize ); -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] 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 @@ -652,7 +698,7 @@ sockopt_impl!( libc::SO_ACCEPTCONN, bool ); -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] sockopt_impl!( /// Bind this socket to a particular device like “eth0”. BindToDevice, @@ -661,7 +707,7 @@ sockopt_impl!( libc::SO_BINDTODEVICE, OsString<[u8; libc::IFNAMSIZ]> ); -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -673,7 +719,7 @@ sockopt_impl!( libc::SO_ORIGINAL_DST, libc::sockaddr_in ); -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] sockopt_impl!( #[allow(missing_docs)] // Not documented by Linux! @@ -683,7 +729,7 @@ sockopt_impl!( libc::IP6T_SO_ORIGINAL_DST, libc::sockaddr_in6 ); -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] sockopt_impl!( /// Specifies exact type of timestamping information collected by the kernel /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) @@ -693,7 +739,7 @@ sockopt_impl!( libc::SO_TIMESTAMPING, super::TimestampingFlag ); -#[cfg(not(any(target_os = "aix", target_os = "haiku", target_os = "redox")))] +#[cfg(not(any(target_os = "aix", target_os = "haiku", target_os = "hurd", target_os = "redox")))] sockopt_impl!( /// Enable or disable the receiving of the `SO_TIMESTAMP` control message. ReceiveTimestamp, @@ -702,7 +748,7 @@ sockopt_impl!( libc::SO_TIMESTAMP, bool ); -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] sockopt_impl!( /// Enable or disable the receiving of the `SO_TIMESTAMPNS` control message. ReceiveTimestampns, @@ -719,9 +765,9 @@ sockopt_impl!( Both, libc::SOL_SOCKET, libc::SO_TS_CLOCK, - i32 + super::SocketTimestamp ); -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -806,7 +852,7 @@ sockopt_impl!( libc::SO_MARK, u32 ); -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] sockopt_impl!( /// Enable or disable the receiving of the `SCM_CREDENTIALS` control /// message. @@ -828,13 +874,7 @@ sockopt_impl!( 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(any(linux_android, apple_targets, target_os = "netbsd"))] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -846,15 +886,7 @@ sockopt_impl!( 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(any(linux_android, target_os = "freebsd", apple_targets, netbsdlike))] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -866,13 +898,7 @@ sockopt_impl!( libc::IPV6_RECVPKTINFO, bool ); -#[cfg(any( - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", -))] +#[cfg(bsd)] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -884,13 +910,7 @@ sockopt_impl!( libc::IP_RECVIF, bool ); -#[cfg(any( - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", -))] +#[cfg(bsd)] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -902,7 +922,7 @@ sockopt_impl!( libc::IP_RECVDSTADDR, bool ); -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +#[cfg(any(linux_android, target_os = "freebsd"))] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -948,7 +968,7 @@ sockopt_impl!( libc::SO_TXTIME, libc::sock_txtime ); -#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] +#[cfg(any(linux_android, target_os = "fuchsia"))] 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 @@ -969,7 +989,7 @@ sockopt_impl!( libc::IPV6_V6ONLY, bool ); -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] sockopt_impl!( /// Enable extended reliable error message passing. Ipv4RecvErr, @@ -978,7 +998,7 @@ sockopt_impl!( libc::IP_RECVERR, bool ); -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] sockopt_impl!( /// Control receiving of asynchronous error options. Ipv6RecvErr, @@ -987,7 +1007,7 @@ sockopt_impl!( libc::IPV6_RECVERR, bool ); -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] sockopt_impl!( /// Fetch the current system-estimated Path MTU. IpMtu, @@ -996,7 +1016,7 @@ sockopt_impl!( libc::IP_MTU, libc::c_int ); -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +#[cfg(any(linux_android, target_os = "freebsd"))] sockopt_impl!( /// Set or retrieve the current time-to-live field that is used in every /// packet sent from this socket. @@ -1006,7 +1026,7 @@ sockopt_impl!( libc::IP_TTL, libc::c_int ); -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +#[cfg(any(linux_android, target_os = "freebsd"))] sockopt_impl!( /// Set the unicast hop limit for the socket. Ipv6Ttl, @@ -1015,7 +1035,7 @@ sockopt_impl!( libc::IPV6_UNICAST_HOPS, libc::c_int ); -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +#[cfg(any(linux_android, target_os = "freebsd"))] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -1027,7 +1047,7 @@ sockopt_impl!( libc::IPV6_ORIGDSTADDR, bool ); -#[cfg(any(target_os = "ios", target_os = "macos"))] +#[cfg(apple_targets)] sockopt_impl!( /// Set "don't fragment packet" flag on the IP packet. IpDontFrag, @@ -1036,12 +1056,7 @@ sockopt_impl!( libc::IP_DONTFRAG, bool ); -#[cfg(any( - target_os = "android", - target_os = "ios", - target_os = "linux", - target_os = "macos", -))] +#[cfg(any(linux_android, apple_targets))] sockopt_impl!( /// Set "don't fragment packet" flag on the IPv6 packet. Ipv6DontFrag, @@ -1053,13 +1068,13 @@ sockopt_impl!( #[allow(missing_docs)] // Not documented by Linux! -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[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"))] +#[cfg(linux_android)] impl SetSockOpt for AlgSetAeadAuthSize { type Val = usize; @@ -1079,18 +1094,18 @@ impl SetSockOpt for AlgSetAeadAuthSize { #[allow(missing_docs)] // Not documented by Linux! -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[derive(Clone, Debug)] pub struct AlgSetKey<T>(::std::marker::PhantomData<T>); -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] impl<T> Default for AlgSetKey<T> { fn default() -> Self { AlgSetKey(Default::default()) } } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] impl<T> SetSockOpt for AlgSetKey<T> where T: AsRef<[u8]> + Clone, @@ -1103,7 +1118,54 @@ where fd.as_fd().as_raw_fd(), libc::SOL_ALG, libc::ALG_SET_KEY, - val.as_ref().as_ptr() as *const _, + val.as_ref().as_ptr().cast(), + val.as_ref().len() as libc::socklen_t, + ); + Errno::result(res).map(drop) + } + } +} + +/// Set the Upper Layer Protocol (ULP) on the TCP socket. +/// +/// For example, to enable the TLS ULP on a socket, the C function call would be: +/// +/// ```c +/// setsockopt(sock, SOL_TCP, TCP_ULP, "tls", sizeof("tls")); +/// ``` +/// +/// ... and the `nix` equivalent is: +/// +/// ```ignore,rust +/// setsockopt(sock, TcpUlp::default(), b"tls"); +/// ``` +/// +/// Note that the ULP name does not need a trailing NUL terminator (`\0`). +#[cfg(linux_android)] +#[derive(Clone, Debug)] +pub struct TcpUlp<T>(::std::marker::PhantomData<T>); + +#[cfg(linux_android)] +impl<T> Default for TcpUlp<T> { + fn default() -> Self { + TcpUlp(Default::default()) + } +} + +#[cfg(linux_android)] +impl<T> SetSockOpt for TcpUlp<T> +where + T: AsRef<[u8]> + Clone, +{ + type Val = T; + + fn set<F: AsFd>(&self, fd: &F, val: &Self::Val) -> Result<()> { + unsafe { + let res = libc::setsockopt( + fd.as_fd().as_raw_fd(), + libc::SOL_TCP, + libc::TCP_ULP, + val.as_ref().as_ptr().cast(), val.as_ref().len() as libc::socklen_t, ); Errno::result(res).map(drop) @@ -1111,6 +1173,113 @@ where } } +/// Value used with the [`TcpTlsTx`] and [`TcpTlsRx`] socket options. +#[cfg(target_os = "linux")] +#[derive(Copy, Clone, Debug)] +pub enum TlsCryptoInfo { + /// AES-128-GCM + Aes128Gcm(libc::tls12_crypto_info_aes_gcm_128), + + /// AES-256-GCM + Aes256Gcm(libc::tls12_crypto_info_aes_gcm_256), + + /// CHACHA20-POLY1305 + Chacha20Poly1305(libc::tls12_crypto_info_chacha20_poly1305), +} + +/// Set the Kernel TLS write parameters on the TCP socket. +/// +/// For example, the C function call would be: +/// +/// ```c +/// setsockopt(sock, SOL_TLS, TLS_TX, &crypto_info, sizeof(crypto_info)); +/// ``` +/// +/// ... and the `nix` equivalent is: +/// +/// ```ignore,rust +/// setsockopt(sock, TcpTlsTx, &crypto_info); +/// ``` +#[cfg(target_os = "linux")] +#[derive(Copy, Clone, Debug)] +pub struct TcpTlsTx; + +#[cfg(target_os = "linux")] +impl SetSockOpt for TcpTlsTx { + type Val = TlsCryptoInfo; + + fn set<F: AsFd>(&self, fd: &F, val: &Self::Val) -> Result<()> { + let (ffi_ptr, ffi_len) = match val { + TlsCryptoInfo::Aes128Gcm(crypto_info) => { + (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info)) + } + TlsCryptoInfo::Aes256Gcm(crypto_info) => { + (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info)) + } + TlsCryptoInfo::Chacha20Poly1305(crypto_info) => { + (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info)) + } + }; + unsafe { + let res = libc::setsockopt( + fd.as_fd().as_raw_fd(), + libc::SOL_TLS, + libc::TLS_TX, + ffi_ptr, + ffi_len as libc::socklen_t, + ); + Errno::result(res).map(drop) + } + } +} + +/// Set the Kernel TLS read parameters on the TCP socket. +/// +/// For example, the C function call would be: +/// +/// ```c +/// setsockopt(sock, SOL_TLS, TLS_RX, &crypto_info, sizeof(crypto_info)); +/// ``` +/// +/// ... and the `nix` equivalent is: +/// +/// ```ignore,rust +/// setsockopt(sock, TcpTlsRx, &crypto_info); +/// ``` +#[cfg(target_os = "linux")] +#[derive(Copy, Clone, Debug)] +pub struct TcpTlsRx; + +#[cfg(target_os = "linux")] +impl SetSockOpt for TcpTlsRx { + type Val = TlsCryptoInfo; + + fn set<F: AsFd>(&self, fd: &F, val: &Self::Val) -> Result<()> { + let (ffi_ptr, ffi_len) = match val { + TlsCryptoInfo::Aes128Gcm(crypto_info) => { + (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info)) + } + TlsCryptoInfo::Aes256Gcm(crypto_info) => { + (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info)) + } + TlsCryptoInfo::Chacha20Poly1305(crypto_info) => { + (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info)) + } + }; + unsafe { + let res = libc::setsockopt( + fd.as_fd().as_raw_fd(), + libc::SOL_TLS, + libc::TLS_RX, + ffi_ptr, + ffi_len as libc::socklen_t, + ); + Errno::result(res).map(drop) + } + } +} + + /* * * ===== Accessor helpers ===== @@ -1158,7 +1327,7 @@ impl<T> Get<T> for GetStruct<T> { } fn ffi_ptr(&mut self) -> *mut c_void { - self.val.as_mut_ptr() as *mut c_void + self.val.as_mut_ptr().cast() } fn ffi_len(&mut self) -> *mut socklen_t { @@ -1171,7 +1340,7 @@ impl<T> Get<T> for GetStruct<T> { mem::size_of::<T>(), "invalid getsockopt implementation" ); - self.val.assume_init() + unsafe { self.val.assume_init() } } } @@ -1209,7 +1378,7 @@ impl Get<bool> for GetBool { } fn ffi_ptr(&mut self) -> *mut c_void { - self.val.as_mut_ptr() as *mut c_void + self.val.as_mut_ptr().cast() } fn ffi_len(&mut self) -> *mut socklen_t { @@ -1222,7 +1391,7 @@ impl Get<bool> for GetBool { mem::size_of::<c_int>(), "invalid getsockopt implementation" ); - self.val.assume_init() != 0 + unsafe { self.val.assume_init() != 0 } } } @@ -1243,7 +1412,7 @@ impl<'a> Set<'a, bool> for SetBool { } fn ffi_len(&self) -> socklen_t { - mem::size_of::<c_int>() as socklen_t + mem::size_of_val(&self.val) as socklen_t } } @@ -1262,7 +1431,7 @@ impl Get<u8> for GetU8 { } fn ffi_ptr(&mut self) -> *mut c_void { - self.val.as_mut_ptr() as *mut c_void + self.val.as_mut_ptr().cast() } fn ffi_len(&mut self) -> *mut socklen_t { @@ -1275,7 +1444,7 @@ impl Get<u8> for GetU8 { mem::size_of::<u8>(), "invalid getsockopt implementation" ); - self.val.assume_init() + unsafe { self.val.assume_init() } } } @@ -1294,7 +1463,7 @@ impl<'a> Set<'a, u8> for SetU8 { } fn ffi_len(&self) -> socklen_t { - mem::size_of::<c_int>() as socklen_t + mem::size_of_val(&self.val) as socklen_t } } @@ -1313,7 +1482,7 @@ impl Get<usize> for GetUsize { } fn ffi_ptr(&mut self) -> *mut c_void { - self.val.as_mut_ptr() as *mut c_void + self.val.as_mut_ptr().cast() } fn ffi_len(&mut self) -> *mut socklen_t { @@ -1326,7 +1495,7 @@ impl Get<usize> for GetUsize { mem::size_of::<c_int>(), "invalid getsockopt implementation" ); - self.val.assume_init() as usize + unsafe { self.val.assume_init() as usize } } } @@ -1345,7 +1514,7 @@ impl<'a> Set<'a, usize> for SetUsize { } fn ffi_len(&self) -> socklen_t { - mem::size_of::<c_int>() as socklen_t + mem::size_of_val(&self.val) as socklen_t } } @@ -1364,7 +1533,7 @@ impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> { } fn ffi_ptr(&mut self) -> *mut c_void { - self.val.as_mut_ptr() as *mut c_void + self.val.as_mut_ptr().cast() } fn ffi_len(&mut self) -> *mut socklen_t { @@ -1373,7 +1542,7 @@ impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> { unsafe fn assume_init(self) -> OsString { let len = self.len as usize; - let mut v = self.val.assume_init(); + let mut v = unsafe { self.val.assume_init() }; OsStr::from_bytes(&v.as_mut()[0..len]).to_owned() } } @@ -1391,7 +1560,7 @@ impl<'a> Set<'a, OsString> for SetOsString<'a> { } fn ffi_ptr(&self) -> *const c_void { - self.val.as_bytes().as_ptr() as *const c_void + self.val.as_bytes().as_ptr().cast() } fn ffi_len(&self) -> socklen_t { @@ -1399,72 +1568,3 @@ impl<'a> Set<'a, OsString> for SetOsString<'a> { } } -#[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::*; - - 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); - } - - #[test] - fn is_socket_type_dgram() { - use super::super::*; - - 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); - } - - #[cfg(any(target_os = "freebsd", target_os = "linux"))] - #[test] - fn can_get_listen_on_tcp_socket() { - use super::super::*; - - 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); - } -} diff --git a/third_party/rust/nix/src/sys/stat.rs b/third_party/rust/nix/src/sys/stat.rs index 7e51c03a3f..c5854eec01 100644 --- a/third_party/rust/nix/src/sys/stat.rs +++ b/third_party/rust/nix/src/sys/stat.rs @@ -1,10 +1,6 @@ -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "openbsd"))] +#[cfg(any(apple_targets, target_os = "openbsd"))] pub use libc::c_uint; -#[cfg(any( - target_os = "netbsd", - target_os = "freebsd", - target_os = "dragonfly" -))] +#[cfg(any(target_os = "netbsd", freebsdlike))] pub use libc::c_ulong; pub use libc::stat as FileStat; pub use libc::{dev_t, mode_t}; @@ -43,7 +39,7 @@ libc_bitflags! { S_IXUSR; /// Read write and execute for group. S_IRWXG; - /// Read fr group. + /// Read for group. S_IRGRP; /// Write for group. S_IWGRP; @@ -65,26 +61,14 @@ libc_bitflags! { } } -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "openbsd"))] +#[cfg(any(apple_targets, target_os = "openbsd"))] pub type type_of_file_flag = c_uint; -#[cfg(any( - target_os = "netbsd", - target_os = "freebsd", - target_os = "dragonfly" -))] +#[cfg(any(freebsdlike, target_os = "netbsd"))] 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" -))] +#[cfg(bsd)] 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; @@ -101,7 +85,7 @@ libc_bitflags! { #[cfg(any(target_os = "dragonfly"))] SF_NOHISTORY; /// The file may not be renamed or deleted. - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg(freebsdlike)] SF_NOUNLINK; /// Mask of superuser changeable flags SF_SETTABLE; @@ -121,14 +105,13 @@ libc_bitflags! { #[cfg(any(target_os = "dragonfly"))] UF_CACHE; /// File is compressed at the file system level. - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] 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", + apple_targets, ))] UF_HIDDEN; /// The file may not be changed. @@ -138,7 +121,7 @@ libc_bitflags! { #[cfg(any(target_os = "dragonfly"))] UF_NOHISTORY; /// The file may not be renamed or deleted. - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg(freebsdlike)] UF_NOUNLINK; /// The file is offline, or has the Windows and CIFS /// `FILE_ATTRIBUTE_OFFLINE` attribute. @@ -162,7 +145,7 @@ libc_bitflags! { #[cfg(any(target_os = "freebsd"))] UF_SYSTEM; /// File renames and deletes are tracked. - #[cfg(any(target_os = "macos", target_os = "ios"))] + #[cfg(apple_targets)] UF_TRACKED; #[cfg(any(target_os = "dragonfly"))] UF_XLINK; @@ -184,20 +167,15 @@ pub fn mknod<P: ?Sized + NixPath>( } /// 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())))] +#[cfg(not(any(apple_targets, target_os = "redox", target_os = "haiku")))] pub fn mknodat<P: ?Sized + NixPath>( - dirfd: RawFd, + dirfd: Option<RawFd>, path: &P, kind: SFlag, perm: Mode, dev: dev_t, ) -> Result<()> { + let dirfd = at_rawfd(dirfd); let res = path.with_nix_path(|cstr| unsafe { libc::mknodat( dirfd, @@ -211,19 +189,16 @@ pub fn mknodat<P: ?Sized + NixPath>( } #[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) @@ -268,12 +243,12 @@ pub fn fstat(fd: RawFd) -> Result<FileStat> { } #[cfg(not(target_os = "redox"))] -#[cfg_attr(docsrs, doc(cfg(all())))] pub fn fstatat<P: ?Sized + NixPath>( - dirfd: RawFd, + dirfd: Option<RawFd>, pathname: &P, f: AtFlags, ) -> Result<FileStat> { + let dirfd = at_rawfd(dirfd); let mut dst = mem::MaybeUninit::uninit(); let res = pathname.with_nix_path(|cstr| unsafe { libc::fstatat( @@ -324,7 +299,6 @@ pub enum FchmodatFlags { /// /// [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, @@ -383,12 +357,10 @@ pub fn utimes<P: ?Sized + NixPath>( #[cfg(any( target_os = "linux", target_os = "haiku", - target_os = "ios", - target_os = "macos", + apple_targets, target_os = "freebsd", target_os = "netbsd" ))] -#[cfg_attr(docsrs, doc(cfg(all())))] pub fn lutimes<P: ?Sized + NixPath>( path: &P, atime: &TimeVal, @@ -404,6 +376,9 @@ pub fn lutimes<P: ?Sized + NixPath>( /// Change the access and modification times of the file specified by a file descriptor. /// +/// If you want to set the timestamp to now, use `TimeSpec::UTIME_NOW`. Use +/// `TimeSpec::UTIME_OMIT` if you don't want to change it. +/// /// # References /// /// [futimens(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html). @@ -436,11 +411,13 @@ pub enum UtimensatFlags { /// `utimes(path, times)`. The latter is a deprecated API so prefer using the /// former if the platforms you care about support it. /// +/// If you want to set the timestamp to now, use `TimeSpec::UTIME_NOW`. Use +/// `TimeSpec::UTIME_OMIT` if you don't want to change 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, @@ -466,12 +443,12 @@ pub fn utimensat<P: ?Sized + NixPath>( } #[cfg(not(target_os = "redox"))] -#[cfg_attr(docsrs, doc(cfg(all())))] pub fn mkdirat<P: ?Sized + NixPath>( - fd: RawFd, + fd: Option<RawFd>, path: &P, mode: Mode, ) -> Result<()> { + let fd = at_rawfd(fd); let res = path.with_nix_path(|cstr| unsafe { libc::mkdirat(fd, cstr.as_ptr(), mode.bits() as mode_t) })?; diff --git a/third_party/rust/nix/src/sys/statfs.rs b/third_party/rust/nix/src/sys/statfs.rs index 5111df2e6e..b2315f4ceb 100644 --- a/third_party/rust/nix/src/sys/statfs.rs +++ b/third_party/rust/nix/src/sys/statfs.rs @@ -1,7 +1,7 @@ //! Get filesystem statistics, non-portably //! //! See [`statvfs`](crate::sys::statvfs) for a portable alternative. -#[cfg(not(any(target_os = "linux", target_os = "android")))] +#[cfg(not(linux_android))] use std::ffi::CStr; use std::fmt::{self, Debug}; use std::mem; @@ -9,16 +9,7 @@ use std::os::unix::io::{AsFd, 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" - ) -))] +#[cfg(all(feature = "mount", bsd))] use crate::mount::MntFlags; #[cfg(target_os = "linux")] use crate::sys::statvfs::FsFlags; @@ -26,15 +17,13 @@ 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"))] { + if #[cfg(any(linux_android, target_os = "fuchsia"))] { type type_of_statfs = libc::statfs64; const LIBC_FSTATFS: unsafe extern fn (fd: libc::c_int, buf: *mut type_of_statfs) -> libc::c_int @@ -62,10 +51,12 @@ pub struct Statfs(type_of_statfs); type fs_type_t = u32; #[cfg(target_os = "android")] type fs_type_t = libc::c_ulong; -#[cfg(all(target_os = "linux", target_arch = "s390x"))] +#[cfg(all(target_os = "linux", target_arch = "s390x", not(target_env = "musl")))] 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 = "ohos"))] +type fs_type_t = libc::c_ulong; #[cfg(all(target_os = "linux", target_env = "uclibc"))] type fs_type_t = libc::c_int; #[cfg(all( @@ -73,6 +64,7 @@ type fs_type_t = libc::c_int; not(any( target_arch = "s390x", target_env = "musl", + target_env = "ohos", target_env = "uclibc" )) ))] @@ -84,6 +76,7 @@ type fs_type_t = libc::__fsword_t; target_os = "android", all(target_os = "linux", target_arch = "s390x"), all(target_os = "linux", target_env = "musl"), + all(target_os = "linux", target_env = "ohos"), all( target_os = "linux", not(any(target_arch = "s390x", target_env = "musl")) @@ -94,206 +87,203 @@ 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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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"))] +#[cfg(linux_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") -))] +#[cfg(all(linux_android, not(target_env = "musl"), not(target_env = "ohos")))] #[allow(missing_docs)] pub const XFS_SUPER_MAGIC: FsType = FsType(libc::XFS_SUPER_MAGIC as fs_type_t); @@ -302,39 +292,33 @@ impl Statfs { #[cfg(not(any( target_os = "openbsd", target_os = "dragonfly", - target_os = "ios", - target_os = "macos" + apple_targets, )))] - #[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())))] + #[cfg(not(linux_android))] 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())))] + #[cfg(apple_targets)] 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())))] + #[cfg(all(target_os = "linux", target_arch = "s390x", not(target_env = "musl")))] pub fn optimal_transfer_size(&self) -> u32 { self.0.f_bsize } @@ -342,9 +326,9 @@ impl Statfs { /// Optimal transfer block size #[cfg(any( target_os = "android", - all(target_os = "linux", target_env = "musl") + all(target_os = "linux", target_env = "musl"), + all(target_os = "linux", target_env = "ohos") ))] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn optimal_transfer_size(&self) -> libc::c_ulong { self.0.f_bsize } @@ -355,46 +339,41 @@ impl Statfs { not(any( target_arch = "s390x", target_env = "musl", + target_env = "ohos", 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())))] + #[cfg(any(apple_targets, target_os = "openbsd"))] 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())))] + #[cfg(all(target_os = "linux", target_arch = "s390x", not(target_env = "musl")))] pub fn block_size(&self) -> u32 { self.0.f_bsize } @@ -402,7 +381,13 @@ impl Statfs { /// 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 = "ohos"))] pub fn block_size(&self) -> libc::c_ulong { self.0.f_bsize } @@ -410,7 +395,6 @@ impl Statfs { /// 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 } @@ -422,47 +406,34 @@ impl Statfs { not(any( target_arch = "s390x", target_env = "musl", + target_env = "ohos", 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())))] + #[cfg(all(feature = "mount", bsd))] #[allow(clippy::unnecessary_cast)] // Not unnecessary on all arches pub fn flags(&self) -> MntFlags { MntFlags::from_bits_truncate(self.0.f_flags as i32) @@ -472,35 +443,30 @@ impl Statfs { // 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())))] + #[cfg(all(target_os = "linux", target_arch = "s390x", not(target_env = "musl")))] 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 } @@ -511,173 +477,141 @@ impl Statfs { not(any( target_arch = "s390x", target_env = "musl", + target_env = "ohos", 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", + apple_targets, + linux_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", + apple_targets, + linux_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())))] + #[cfg(any(apple_targets, linux_android, target_os = "fuchsia"))] 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", + apple_targets, + linux_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", + apple_targets, + linux_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 } @@ -699,16 +633,7 @@ impl Debug for Statfs { 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" - ) - ))] + #[cfg(all(feature = "mount", bsd))] ds.field("flags", &self.flags()); ds.finish() } @@ -747,107 +672,3 @@ pub fn fstatfs<Fd: AsFd>(fd: Fd) -> Result<Statfs> { .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/third_party/rust/nix/src/sys/statvfs.rs b/third_party/rust/nix/src/sys/statvfs.rs index 35424e5e27..db1abdd4fe 100644 --- a/third_party/rust/nix/src/sys/statvfs.rs +++ b/third_party/rust/nix/src/sys/statvfs.rs @@ -21,44 +21,34 @@ libc_bitflags!( #[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())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] ST_NOEXEC; /// All IO should be done synchronously - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] ST_SYNCHRONOUS; /// Allow mandatory locks on the filesystem - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] ST_NOATIME; /// Do not update access times on files - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] 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())))] + #[cfg(any(target_os = "android", all(target_os = "linux", not(target_env = "musl"), not(target_env = "ohos"))))] ST_RELATIME; } ); @@ -114,13 +104,18 @@ impl Statvfs { } /// Get the file system id + #[cfg(not(target_os = "hurd"))] pub fn filesystem_id(&self) -> c_ulong { self.0.f_fsid } + /// Get the file system id + #[cfg(target_os = "hurd")] + pub fn filesystem_id(&self) -> u64 { + 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) } @@ -153,20 +148,3 @@ pub fn fstatvfs<Fd: AsFd>(fd: Fd) -> Result<Statvfs> { .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/third_party/rust/nix/src/sys/termios.rs b/third_party/rust/nix/src/sys/termios.rs index ecaa3eaf8f..e006c2f1b0 100644 --- a/third_party/rust/nix/src/sys/termios.rs +++ b/third_party/rust/nix/src/sys/termios.rs @@ -85,28 +85,8 @@ //! //! 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" -)] +#![cfg_attr(bsd, doc = " ```rust,ignore")] +#![cfg_attr(not(bsd), doc = " ```rust")] //! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetspeed, Termios}; //! # fn main() { //! # let mut t: Termios = unsafe { std::mem::zeroed() }; @@ -118,28 +98,8 @@ //! //! 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" -)] +#![cfg_attr(bsd, doc = " ```rust")] +#![cfg_attr(not(bsd), doc = " ```rust,ignore")] //! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetspeed, Termios}; //! # fn main() { //! # let mut t: Termios = unsafe { std::mem::zeroed() }; @@ -151,28 +111,8 @@ //! //! 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" -)] +#![cfg_attr(bsd, doc = " ```rust")] +#![cfg_attr(not(bsd), doc = " ```rust,ignore")] //! # use nix::sys::termios::{BaudRate, cfgetispeed, cfsetspeed, Termios}; //! # fn main() { //! # let mut t: Termios = unsafe { std::mem::zeroed() }; @@ -185,28 +125,8 @@ //! 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" -)] +#![cfg_attr(bsd, doc = " ```rust")] +#![cfg_attr(not(bsd), doc = " ```rust,ignore")] //! # use nix::sys::termios::{cfsetispeed, cfsetospeed, cfsetspeed, Termios}; //! # fn main() { //! # let mut t: Termios = unsafe { std::mem::zeroed() }; @@ -246,7 +166,7 @@ pub struct Termios { /// 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",))] + #[cfg(linux_android)] pub line_discipline: libc::cc_t, /// Line discipline (see `termios.c_line` documentation) #[cfg(target_os = "haiku")] @@ -266,11 +186,7 @@ impl Termios { 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", - ))] + #[cfg(any(linux_android, target_os = "haiku"))] { termios.c_line = self.line_discipline; } @@ -292,11 +208,7 @@ impl Termios { 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", - ))] + #[cfg(any(linux_android, target_os = "haiku"))] { termios.c_line = self.line_discipline; } @@ -312,11 +224,7 @@ impl Termios { self.control_flags = ControlFlags::from_bits_retain(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", - ))] + #[cfg(any(linux_android, target_os = "haiku"))] { self.line_discipline = termios.c_line; } @@ -332,11 +240,7 @@ impl From<libc::termios> for Termios { 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", - ))] + #[cfg(any(linux_android, target_os = "haiku"))] line_discipline: termios.c_line, } } @@ -356,8 +260,13 @@ libc_enum! { /// /// B0 is special and will disable the port. #[cfg_attr(target_os = "haiku", repr(u8))] - #[cfg_attr(all(any(target_os = "ios", target_os = "macos"), target_pointer_width = "64"), repr(u64))] - #[cfg_attr(all(not(all(any(target_os = "ios", target_os = "macos"), target_pointer_width = "64")), not(target_os = "haiku")), repr(u32))] + #[cfg_attr(target_os = "hurd", repr(i32))] + #[cfg_attr(all(apple_targets, target_pointer_width = "64"), repr(u64))] + #[cfg_attr(all( + not(all(apple_targets, target_pointer_width = "64")), + not(target_os = "haiku"), + not(target_os = "hurd") + ), repr(u32))] #[non_exhaustive] pub enum BaudRate { B0, @@ -373,110 +282,62 @@ libc_enum! { 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())))] + #[cfg(bsd)] 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())))] + #[cfg(bsd)] 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())))] + #[cfg(bsd)] B28800, B38400, #[cfg(not(target_os = "aix"))] - #[cfg_attr(docsrs, doc(cfg(all())))] B57600, - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(bsd)] B76800, #[cfg(not(target_os = "aix"))] - #[cfg_attr(docsrs, doc(cfg(all())))] B115200, - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(solarish)] B153600, #[cfg(not(target_os = "aix"))] - #[cfg_attr(docsrs, doc(cfg(all())))] B230400, - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(solarish)] B307200, - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, + solarish, target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + target_os = "netbsd"))] B460800, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] B500000, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] B576000, - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, + solarish, target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + target_os = "netbsd"))] B921600, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] B1000000, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] B1152000, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] B1500000, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] 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" -))] +#[cfg(bsd)] impl From<BaudRate> for u32 { fn from(b: BaudRate) -> u32 { b as u32 @@ -542,80 +403,57 @@ libc_enum! { } // 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 { - #[cfg(not(target_os = "aix"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(not(any(target_os = "aix", target_os = "haiku")))] VDISCARD, - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "aix", - target_os = "solaris"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, + solarish, + target_os = "aix"))] 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())))] + #[cfg(any(freebsdlike, solarish))] VERASE2, VINTR, VKILL, + #[cfg(not(target_os = "haiku"))] VLNEXT, #[cfg(not(any(all(target_os = "linux", target_arch = "sparc64"), - target_os = "illumos", target_os = "solaris", target_os = "aix")))] - #[cfg_attr(docsrs, doc(cfg(all())))] + solarish, target_os = "aix", target_os = "haiku")))] VMIN, VQUIT, + #[cfg(not(target_os = "haiku"))] 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())))] + #[cfg(any(bsd, solarish))] 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())))] + #[cfg(any(solarish, target_os = "haiku"))] VSWTCH, #[cfg(not(any(all(target_os = "linux", target_arch = "sparc64"), - target_os = "illumos", target_os = "solaris", target_os = "aix")))] - #[cfg_attr(docsrs, doc(cfg(all())))] + solarish, target_os = "aix", target_os = "haiku")))] VTIME, - #[cfg(not(target_os = "aix"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(not(any(target_os = "aix", target_os = "haiku")))] 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", + solarish, target_os = "aix", + target_os = "haiku", ))] impl SpecialCharacterIndices { pub const VMIN: SpecialCharacterIndices = SpecialCharacterIndices::VEOF; @@ -623,17 +461,7 @@ impl SpecialCharacterIndices { } pub use libc::NCCS; -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "aix", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" -))] -#[cfg_attr(docsrs, doc(cfg(all())))] +#[cfg(any(linux_android, target_os = "aix", bsd))] pub use libc::_POSIX_VDISABLE; libc_bitflags! { @@ -651,13 +479,10 @@ libc_bitflags! { 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())))] + #[cfg(any(linux_android, apple_targets))] IUTF8; } } @@ -666,209 +491,119 @@ libc_bitflags! { /// Flags for configuring the output mode of a terminal pub struct OutputFlags: tcflag_t { OPOST; - #[cfg(any(target_os = "android", + #[cfg(any(linux_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", + #[cfg(any(linux_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())))] + apple_targets))] OFDEL as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] NL0 as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] NL1 as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] CR0 as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] CR1 as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] CR2 as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] CR3 as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "freebsd", target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] TAB0 as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] TAB1 as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] TAB2 as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "freebsd", target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] TAB3 as tcflag_t; - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] XTABS; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] BS0 as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] BS1 as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] VT0 as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] VT1 as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] FF0 as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] 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())))] + #[cfg(bsd)] OXTABS; - #[cfg(any(target_os = "freebsd", - target_os = "dragonfly", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(bsd)] 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", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] NLDLY as tcflag_t; // FIXME: Datatype needs to be corrected in libc for mac - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] CRDLY as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "freebsd", target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] TABDLY as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] BSDLY as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] VTDLY as tcflag_t; - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, target_os = "haiku", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + apple_targets))] FFDLY as tcflag_t; } } @@ -876,13 +611,7 @@ libc_bitflags! { 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())))] + #[cfg(bsd)] CIGNORE; CS5; CS6; @@ -895,54 +624,30 @@ libc_bitflags! { HUPCL; CLOCAL; #[cfg(not(any(target_os = "redox", target_os = "aix")))] - #[cfg_attr(docsrs, doc(cfg(all())))] CRTSCTS; - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] CBAUDEX; - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(bsd)] MDMBUF; - #[cfg(any(target_os = "netbsd", target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(netbsdlike)] CHWFLOW; - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(freebsdlike, netbsdlike))] CCTS_OFLOW; - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(freebsdlike, netbsdlike))] CRTS_IFLOW; - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] CDTR_IFLOW; - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] CDSR_OFLOW; - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] CCAR_OFLOW; // Bitmasks for use with ControlFlags to select specific settings @@ -957,58 +662,35 @@ 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())))] + #[cfg(bsd)] ALTWERASE; IEXTEN; #[cfg(not(any(target_os = "redox", target_os = "haiku", target_os = "aix")))] - #[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())))] + #[cfg(bsd)] 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"))] { + if #[cfg(bsd)] { /// Get input baud rate (see /// [cfgetispeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html)). /// @@ -1141,7 +823,6 @@ pub fn cfmakeraw(termios: &mut Termios) { /// /// 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 { @@ -1242,18 +923,3 @@ pub fn tcgetsid<Fd: AsFd>(fd: Fd) -> Result<Pid> { 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/third_party/rust/nix/src/sys/time.rs b/third_party/rust/nix/src/sys/time.rs index a0160e21ff..af436cabd5 100644 --- a/third_party/rust/nix/src/sys/time.rs +++ b/third_party/rust/nix/src/sys/time.rs @@ -2,7 +2,6 @@ // 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}; @@ -18,7 +17,7 @@ const fn zero_init_timespec() -> timespec { all( any( target_os = "freebsd", - target_os = "illumos", + solarish, target_os = "linux", target_os = "netbsd" ), @@ -88,7 +87,7 @@ pub(crate) mod timer { Interval(TimeSpec), } - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] bitflags! { /// Flags that are used for arming the timer. #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] @@ -97,12 +96,7 @@ pub(crate) mod timer { const TFD_TIMER_CANCEL_ON_SET = libc::TFD_TIMER_CANCEL_ON_SET; } } - #[cfg(any( - target_os = "freebsd", - target_os = "netbsd", - target_os = "dragonfly", - target_os = "illumos" - ))] + #[cfg(any(freebsdlike, target_os = "netbsd", solarish))] bitflags! { /// Flags that are used for arming the timer. #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] @@ -334,6 +328,17 @@ impl TimeValLike for TimeSpec { } impl TimeSpec { + /// Leave the timestamp unchanged. + #[cfg(not(target_os = "redox"))] + // At the time of writing this PR, redox does not support this feature + pub const UTIME_OMIT: TimeSpec = + TimeSpec::new(0, libc::UTIME_OMIT as timespec_tv_nsec_t); + /// Update the timestamp to `Now` + // At the time of writing this PR, redox does not support this feature + #[cfg(not(target_os = "redox"))] + pub const UTIME_NOW: TimeSpec = + TimeSpec::new(0, libc::UTIME_NOW as timespec_tv_nsec_t); + /// 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 { @@ -712,101 +717,3 @@ fn mod_floor_64(this: i64, other: i64) -> i64 { 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/third_party/rust/nix/src/sys/timerfd.rs b/third_party/rust/nix/src/sys/timerfd.rs index c4337c9dfa..68b06d6322 100644 --- a/third_party/rust/nix/src/sys/timerfd.rs +++ b/third_party/rust/nix/src/sys/timerfd.rs @@ -53,7 +53,7 @@ impl AsFd for TimerFd { impl FromRawFd for TimerFd { unsafe fn from_raw_fd(fd: RawFd) -> Self { TimerFd { - fd: OwnedFd::from_raw_fd(fd), + fd: unsafe { OwnedFd::from_raw_fd(fd) }, } } } diff --git a/third_party/rust/nix/src/sys/uio.rs b/third_party/rust/nix/src/sys/uio.rs index eaf61edfd4..cdf380dd11 100644 --- a/third_party/rust/nix/src/sys/uio.rs +++ b/third_party/rust/nix/src/sys/uio.rs @@ -2,7 +2,7 @@ use crate::errno::Errno; use crate::Result; -use libc::{self, c_int, c_void, off_t, size_t}; +use libc::{self, c_int, off_t, size_t}; use std::io::{IoSlice, IoSliceMut}; use std::os::unix::io::{AsFd, AsRawFd}; @@ -18,7 +18,11 @@ pub fn writev<Fd: AsFd>(fd: Fd, iov: &[IoSlice<'_>]) -> Result<usize> { // // Because it is ABI compatible, a pointer cast here is valid let res = unsafe { - libc::writev(fd.as_fd().as_raw_fd(), iov.as_ptr() as *const libc::iovec, iov.len() as c_int) + libc::writev( + fd.as_fd().as_raw_fd(), + iov.as_ptr().cast(), + iov.len() as c_int, + ) }; Errno::result(res).map(|r| r as usize) @@ -33,7 +37,11 @@ pub fn writev<Fd: AsFd>(fd: Fd, iov: &[IoSlice<'_>]) -> Result<usize> { pub fn readv<Fd: AsFd>(fd: Fd, iov: &mut [IoSliceMut<'_>]) -> Result<usize> { // SAFETY: same as in writev(), IoSliceMut is ABI-compatible with iovec let res = unsafe { - libc::readv(fd.as_fd().as_raw_fd(), iov.as_ptr() as *const libc::iovec, iov.len() as c_int) + libc::readv( + fd.as_fd().as_raw_fd(), + iov.as_ptr().cast(), + iov.len() as c_int, + ) }; Errno::result(res).map(|r| r as usize) @@ -45,9 +53,12 @@ pub fn readv<Fd: AsFd>(fd: Fd, iov: &mut [IoSliceMut<'_>]) -> Result<usize> { /// 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: AsFd>(fd: Fd, iov: &[IoSlice<'_>], offset: off_t) -> Result<usize> { +#[cfg(not(any(target_os = "redox", target_os = "haiku", target_os = "solaris")))] +pub fn pwritev<Fd: AsFd>( + fd: Fd, + iov: &[IoSlice<'_>], + offset: off_t, +) -> Result<usize> { #[cfg(target_env = "uclibc")] let offset = offset as libc::off64_t; // uclibc doesn't use off_t @@ -55,7 +66,7 @@ pub fn pwritev<Fd: AsFd>(fd: Fd, iov: &[IoSlice<'_>], offset: off_t) -> Result<u let res = unsafe { libc::pwritev( fd.as_fd().as_raw_fd(), - iov.as_ptr() as *const libc::iovec, + iov.as_ptr().cast(), iov.len() as c_int, offset, ) @@ -71,8 +82,7 @@ pub fn pwritev<Fd: AsFd>(fd: Fd, iov: &[IoSlice<'_>], offset: off_t) -> Result<u /// 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())))] +#[cfg(not(any(target_os = "redox", target_os = "haiku", target_os = "solaris")))] // Clippy doesn't know that we need to pass iov mutably only because the // mutation happens after converting iov to a pointer #[allow(clippy::needless_pass_by_ref_mut)] @@ -88,7 +98,7 @@ pub fn preadv<Fd: AsFd>( let res = unsafe { libc::preadv( fd.as_fd().as_raw_fd(), - iov.as_ptr() as *const libc::iovec, + iov.as_ptr().cast(), iov.len() as c_int, offset, ) @@ -105,7 +115,7 @@ pub fn pwrite<Fd: AsFd>(fd: Fd, buf: &[u8], offset: off_t) -> Result<usize> { let res = unsafe { libc::pwrite( fd.as_fd().as_raw_fd(), - buf.as_ptr() as *const c_void, + buf.as_ptr().cast(), buf.len() as size_t, offset, ) @@ -122,7 +132,7 @@ pub fn pread<Fd: AsFd>(fd: Fd, buf: &mut [u8], offset: off_t) -> Result<usize> { let res = unsafe { libc::pread( fd.as_fd().as_raw_fd(), - buf.as_mut_ptr() as *mut c_void, + buf.as_mut_ptr().cast(), buf.len() as size_t, offset, ) @@ -139,8 +149,7 @@ pub fn pread<Fd: AsFd>(fd: Fd, buf: &mut [u8], offset: off_t) -> Result<usize> { /// 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())))] +#[cfg(linux_android)] #[repr(C)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct RemoteIoVec { @@ -173,7 +182,7 @@ feature! { /// [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")))] +#[cfg(all(linux_android, not(target_env = "uclibc")))] pub fn process_vm_writev( pid: crate::unistd::Pid, local_iov: &[IoSlice<'_>], @@ -181,8 +190,8 @@ pub fn process_vm_writev( { 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) + local_iov.as_ptr().cast(), local_iov.len() as libc::c_ulong, + remote_iov.as_ptr().cast(), remote_iov.len() as libc::c_ulong, 0) }; Errno::result(res).map(|r| r as usize) @@ -208,7 +217,7 @@ pub fn process_vm_writev( /// [`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")))] +#[cfg(all(linux_android, not(target_env = "uclibc")))] pub fn process_vm_readv( pid: crate::unistd::Pid, local_iov: &mut [IoSliceMut<'_>], @@ -216,8 +225,8 @@ pub fn process_vm_readv( { 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) + local_iov.as_ptr().cast(), local_iov.len() as libc::c_ulong, + remote_iov.as_ptr().cast(), remote_iov.len() as libc::c_ulong, 0) }; Errno::result(res).map(|r| r as usize) diff --git a/third_party/rust/nix/src/sys/utsname.rs b/third_party/rust/nix/src/sys/utsname.rs index b48ed9f45e..cf4e6cc738 100644 --- a/third_party/rust/nix/src/sys/utsname.rs +++ b/third_party/rust/nix/src/sys/utsname.rs @@ -37,7 +37,7 @@ impl UtsName { } /// NIS or YP domain name of this machine. - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] pub fn domainname(&self) -> &OsStr { cast_and_trim(&self.0.domainname) } @@ -62,24 +62,3 @@ fn cast_and_trim(slice: &[c_char]) -> &OsStr { 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/third_party/rust/nix/src/sys/wait.rs b/third_party/rust/nix/src/sys/wait.rs index f7a63ffcd2..844e165c18 100644 --- a/third_party/rust/nix/src/sys/wait.rs +++ b/third_party/rust/nix/src/sys/wait.rs @@ -24,53 +24,41 @@ libc_bitflags!( /// [`SIGSTOP`](crate::sys::signal::Signal::SIGSTOP) signal. WUNTRACED; /// Report the status of selected processes which have terminated. - #[cfg(any(target_os = "android", + #[cfg(any(linux_android, + apple_targets, 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", + #[cfg(any(linux_android, + apple_targets, 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", + #[cfg(any(linux_android, + apple_targets, 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())))] + #[cfg(any(linux_android, target_os = "redox"))] __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())))] + #[cfg(any(linux_android, target_os = "redox"))] __WALL; /// Wait for "clone" children only. - #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(linux_android, target_os = "redox"))] __WCLONE; } ); @@ -107,16 +95,14 @@ pub enum WaitStatus { /// /// [`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())))] + #[cfg(linux_android)] 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())))] + #[cfg(linux_android)] PtraceSyscall(Pid), /// The process was previously stopped but has resumed execution /// after receiving a `SIGCONT` signal. This is only reported if @@ -139,7 +125,7 @@ impl WaitStatus { Some(p) } StillAlive => None, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] PtraceEvent(p, _, _) | PtraceSyscall(p) => Some(p), } } @@ -173,7 +159,7 @@ fn stop_signal(status: i32) -> Result<Signal> { Signal::try_from(libc::WSTOPSIG(status)) } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] 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 @@ -182,7 +168,7 @@ fn syscall_stop(status: i32) -> bool { libc::WSTOPSIG(status) == libc::SIGTRAP | 0x80 } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] fn stop_additional(status: i32) -> c_int { (status >> 16) as c_int } @@ -216,7 +202,7 @@ impl WaitStatus { WaitStatus::Signaled(pid, term_signal(status)?, dumped_core(status)) } else if stopped(status) { cfg_if! { - if #[cfg(any(target_os = "android", target_os = "linux"))] { + if #[cfg(linux_android)] { fn decode_stopped(pid: Pid, status: i32) -> Result<WaitStatus> { let status_additional = stop_additional(status); Ok(if syscall_stop(status) { @@ -259,7 +245,7 @@ impl WaitStatus { all(target_os = "linux", not(target_env = "uclibc")), ))] unsafe fn from_siginfo(siginfo: &libc::siginfo_t) -> Result<WaitStatus> { - let si_pid = siginfo.si_pid(); + let si_pid = unsafe { siginfo.si_pid() }; if si_pid == 0 { return Ok(WaitStatus::StillAlive); } @@ -267,7 +253,7 @@ impl WaitStatus { assert_eq!(siginfo.si_signo, libc::SIGCHLD); let pid = Pid::from_raw(si_pid); - let si_status = siginfo.si_status(); + let si_status = unsafe { siginfo.si_status() }; let status = match siginfo.si_code { libc::CLD_EXITED => WaitStatus::Exited(pid, si_status), @@ -280,7 +266,7 @@ impl WaitStatus { WaitStatus::Stopped(pid, Signal::try_from(si_status)?) } libc::CLD_CONTINUED => WaitStatus::Continued(pid), - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] libc::CLD_TRAPPED => { if si_status == libc::SIGTRAP | 0x80 { WaitStatus::PtraceSyscall(pid) @@ -354,7 +340,7 @@ pub enum Id<'fd> { /// 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"))] + #[cfg(linux_android)] PIDFd(BorrowedFd<'fd>), /// A helper variant to resolve the unused parameter (`'fd`) problem on platforms /// other than Linux and Android. @@ -376,9 +362,11 @@ pub fn waitid(id: Id, flags: WaitPidFlag) -> Result<WaitStatus> { 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"))] + #[cfg(linux_android)] Id::PIDFd(fd) => (libc::P_PIDFD, fd.as_raw_fd() as libc::id_t), - Id::_Unreachable(_) => unreachable!("This variant could never be constructed"), + Id::_Unreachable(_) => { + unreachable!("This variant could never be constructed") + } }; let siginfo = unsafe { diff --git a/third_party/rust/nix/src/time.rs b/third_party/rust/nix/src/time.rs index 2e03c46cf4..195df71211 100644 --- a/third_party/rust/nix/src/time.rs +++ b/third_party/rust/nix/src/time.rs @@ -1,11 +1,6 @@ +//! Sleep, query system clocks, and set system clock use crate::sys::time::TimeSpec; -#[cfg(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "linux", - target_os = "android", - target_os = "emscripten", -))] +#[cfg(any(freebsdlike, linux_android, target_os = "emscripten"))] #[cfg(feature = "process")] use crate::unistd::Pid; use crate::{Errno, Result}; @@ -14,8 +9,7 @@ use std::mem::MaybeUninit; /// Clock identifier /// -/// Newtype pattern around `clockid_t` (which is just alias). It prevents bugs caused by -/// accidentally passing wrong value. +/// Newtype pattern around [`libc::clockid_t`]. #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct ClockId(clockid_t); @@ -28,14 +22,7 @@ impl ClockId { 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())))] + #[cfg(any(freebsdlike, linux_android, target_os = "emscripten"))] pub fn pid_cpu_clock_id(pid: Pid) -> Result<Self> { clock_getcpuclockid(pid) } @@ -43,7 +30,6 @@ impl ClockId { /// 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) } @@ -55,12 +41,12 @@ impl ClockId { /// Sets time to `timespec` on the clock id #[cfg(not(any( - target_os = "macos", target_os = "ios", + target_os = "tvos", + target_os = "watchos", target_os = "redox", - target_os = "hermit", + target_os = "hermit" )))] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn set_time(self, timespec: TimeSpec) -> Result<()> { clock_settime(self, timespec) } @@ -70,135 +56,103 @@ impl ClockId { self.0 } - #[cfg(any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "linux" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))] + /// Starts at zero when the kernel boots and increments monotonically in SI seconds while the + /// machine is running. 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())))] + /// Like [`CLOCK_BOOTTIME`](ClockId::CLOCK_BOOTTIME), but will wake the system if it is + /// suspended.. + #[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))] pub const CLOCK_BOOTTIME_ALARM: ClockId = ClockId(libc::CLOCK_BOOTTIME_ALARM); + /// Increments in SI seconds. 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())))] + /// Like [`CLOCK_MONOTONIC`](ClockId::CLOCK_MONOTONIC), but optimized for execution time at the expense of accuracy. + #[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))] 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())))] + #[cfg(freebsdlike)] + /// Like [`CLOCK_MONOTONIC`](ClockId::CLOCK_MONOTONIC), but optimized for execution time at the expense of accuracy. 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())))] + #[cfg(freebsdlike)] + /// Like [`CLOCK_MONOTONIC`](ClockId::CLOCK_MONOTONIC), but optimized for accuracy at the expense of execution time. 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())))] + /// Similar to [`CLOCK_MONOTONIC`](ClockId::CLOCK_MONOTONIC), but provides access to a raw + /// hardware-based time that is not subject to NTP adjustments. + #[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))] pub const CLOCK_MONOTONIC_RAW: ClockId = ClockId(libc::CLOCK_MONOTONIC_RAW); #[cfg(any( - target_os = "android", + linux_android, + apple_targets, + freebsdlike, 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())))] + /// Returns the execution time of the calling process. 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())))] + #[cfg(freebsdlike)] + /// Increments when the CPU is running in user or kernel mode pub const CLOCK_PROF: ClockId = ClockId(libc::CLOCK_PROF); + /// Increments as a wall clock should. 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())))] + /// Like [`CLOCK_REALTIME`](ClockId::CLOCK_REALTIME), but not settable. + #[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))] 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())))] + /// Like [`CLOCK_REALTIME`](ClockId::CLOCK_REALTIME), but optimized for execution time at the expense of accuracy. + #[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))] 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())))] + #[cfg(freebsdlike)] + /// Like [`CLOCK_REALTIME`](ClockId::CLOCK_REALTIME), but optimized for execution time at the expense of accuracy. 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())))] + #[cfg(freebsdlike)] + /// Like [`CLOCK_REALTIME`](ClockId::CLOCK_REALTIME), but optimized for accuracy at the expense of execution time. 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())))] + #[cfg(freebsdlike)] + /// Returns the current second without performing a full time counter query, using an in-kernel + /// cached value of the current second. pub const CLOCK_SECOND: ClockId = ClockId(libc::CLOCK_SECOND); + #[allow(missing_docs)] // Undocumented on Linux! #[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())))] + /// International Atomic Time. + /// + /// A nonsettable system-wide clock derived from wall-clock time but ignoring leap seconds. + #[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))] pub const CLOCK_TAI: ClockId = ClockId(libc::CLOCK_TAI); #[cfg(any( - target_os = "android", + linux_android, + apple_targets, + freebsdlike, 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())))] + /// Returns the execution time of the calling thread. 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())))] + #[cfg(freebsdlike)] + /// Starts at zero when the kernel boots and increments monotonically in SI seconds while the + /// machine is running. pub const CLOCK_UPTIME: ClockId = ClockId(libc::CLOCK_UPTIME); - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(freebsdlike)] + /// Like [`CLOCK_UPTIME`](ClockId::CLOCK_UPTIME), but optimized for execution time at the expense of accuracy. 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())))] + #[cfg(freebsdlike)] + /// Like [`CLOCK_UPTIME`](ClockId::CLOCK_UPTIME), but optimized for accuracy at the expense of execution time. 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())))] + #[cfg(freebsdlike)] + /// Increments only when the CPU is running in user mode on behalf of the calling process. pub const CLOCK_VIRTUAL: ClockId = ClockId(libc::CLOCK_VIRTUAL); } @@ -223,7 +177,6 @@ impl std::fmt::Display for ClockId { /// 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 = @@ -247,12 +200,12 @@ pub fn clock_gettime(clock_id: ClockId) -> Result<TimeSpec> { /// 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 = "tvos", + target_os = "watchos", target_os = "redox", - target_os = "hermit", + 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()) }; @@ -261,13 +214,7 @@ pub fn clock_settime(clock_id: ClockId, timespec: TimeSpec) -> Result<()> { /// 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(any(freebsdlike, linux_android, target_os = "emscripten"))] #[cfg(feature = "process")] #[cfg_attr(docsrs, doc(cfg(feature = "process")))] pub fn clock_getcpuclockid(pid: Pid) -> Result<ClockId> { @@ -278,6 +225,61 @@ pub fn clock_getcpuclockid(pid: Pid) -> Result<ClockId> { let res = unsafe { clk_id.assume_init() }; Ok(ClockId::from(res)) } else { - Err(Errno::from_i32(ret)) + Err(Errno::from_raw(ret)) + } +} + +#[cfg(any( + linux_android, + solarish, + freebsdlike, + target_os = "netbsd", + target_os = "hurd", + target_os = "aix" +))] +libc_bitflags! { + /// Flags that are used for arming the timer. + pub struct ClockNanosleepFlags: libc::c_int { + /// Indicates that a requested time value should be treated as absolute instead of + /// relative. + TIMER_ABSTIME; + } +} + +/// Suspend execution of this thread for the amount of time specified by `request` +/// and measured against the clock speficied by `clock_id`. +/// +/// If `flags` is [`TIMER_ABSTIME`](ClockNanosleepFlags::TIMER_ABSTIME), this function will suspend +/// execution until the time value of clock_id reaches the absolute time specified by `request`. If +/// a signal is caught by a signal-catching function, or a signal causes the process to terminate, +/// this sleep is interrrupted. +/// +/// see also [man 3 clock_nanosleep](https://pubs.opengroup.org/onlinepubs/009695399/functions/clock_nanosleep.html) +#[cfg(any( + linux_android, + solarish, + freebsdlike, + target_os = "netbsd", + target_os = "hurd", + target_os = "aix" +))] +pub fn clock_nanosleep( + clock_id: ClockId, + flags: ClockNanosleepFlags, + request: &TimeSpec, +) -> Result<TimeSpec> { + let mut remain = TimeSpec::new(0, 0); + let ret = unsafe { + libc::clock_nanosleep( + clock_id.as_raw(), + flags.bits(), + request.as_ref() as *const _, + remain.as_mut() as *mut _, + ) + }; + if ret == 0 { + Ok(remain) + } else { + Err(Errno::from_raw(ret)) } } diff --git a/third_party/rust/nix/src/unistd.rs b/third_party/rust/nix/src/unistd.rs index bb9f1c1f67..4502766c5d 100644 --- a/third_party/rust/nix/src/unistd.rs +++ b/third_party/rust/nix/src/unistd.rs @@ -1,22 +1,29 @@ //! Safe wrappers around functions found in libc "unistd.h" header -use crate::errno::{self, Errno}; +use crate::errno::Errno; + +#[cfg(any( + all(feature = "fs", not(target_os = "redox")), + all(feature = "process", linux_android) +))] +use crate::fcntl::at_rawfd; #[cfg(not(target_os = "redox"))] #[cfg(feature = "fs")] -use crate::fcntl::{at_rawfd, AtFlags}; +use crate::fcntl::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" - ) +#[cfg(any( + linux_android, + freebsdlike, + solarish, + netbsdlike, + target_os = "emscripten", + target_os = "fuchsia", + target_os = "hurd", + target_os = "redox", ))] +use crate::fcntl::OFlag; +#[cfg(all(feature = "fs", bsd))] use crate::sys::stat::FileFlag; #[cfg(feature = "fs")] use crate::sys::stat::Mode; @@ -24,43 +31,27 @@ 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, + c_char, c_int, c_long, c_uint, gid_t, mode_t, off_t, pid_t, size_t, uid_t, }; 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::os::unix::io::{AsFd, AsRawFd}; +use std::ffi::CString; +use std::ffi::{CStr, OsStr, OsString}; +use std::os::unix::ffi::{OsStrExt, OsStringExt}; +use std::os::unix::io::{AsFd, AsRawFd, OwnedFd, RawFd}; use std::path::PathBuf; use std::{fmt, mem, ptr}; feature! { #![feature = "fs"] - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] pub use self::pivot_root::*; } -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd" -))] +#[cfg(any(freebsdlike, linux_android, target_os = "openbsd"))] pub use self::setres::*; -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd" -))] +#[cfg(any(freebsdlike, linux_android, target_os = "openbsd"))] pub use self::getres::*; feature! { @@ -225,7 +216,12 @@ impl fmt::Display for Pid { /// you are now executing in the parent process or in the child. #[derive(Clone, Copy, Debug)] pub enum ForkResult { - Parent { child: Pid }, + /// This is the parent process of the fork. + Parent { + /// The PID of the fork's child process + child: Pid + }, + /// This is the child process of the fork. Child, } @@ -260,7 +256,7 @@ impl ForkResult { /// } /// 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(); +/// write(std::io::stdout(), "I'm a new child process\n".as_bytes()).ok(); /// unsafe { libc::_exit(0) }; /// } /// Err(_) => println!("Fork failed"), @@ -290,7 +286,7 @@ impl ForkResult { #[inline] pub unsafe fn fork() -> Result<ForkResult> { use self::ForkResult::*; - let res = libc::fork(); + let res = unsafe { libc::fork() }; Errno::result(res).map(|res| match res { 0 => Child, @@ -332,6 +328,9 @@ pub fn setpgid(pid: Pid, pgid: Pid) -> Result<()> { let res = unsafe { libc::setpgid(pid.into(), pgid.into()) }; Errno::result(res).map(drop) } +/// Get process group +/// +/// See Also [`getpgid`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpgid.html) #[inline] pub fn getpgid(pid: Option<Pid>) -> Result<Pid> { let res = unsafe { libc::getpgid(pid.unwrap_or(Pid(0)).into()) }; @@ -366,8 +365,8 @@ feature! { /// 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) }; +pub fn tcgetpgrp<F: AsFd>(fd: F) -> Result<Pid> { + let res = unsafe { libc::tcgetpgrp(fd.as_fd().as_raw_fd()) }; Errno::result(res).map(Pid) } /// Set the terminal foreground process group (see @@ -376,8 +375,8 @@ pub fn tcgetpgrp(fd: c_int) -> Result<Pid> { /// 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()) }; +pub fn tcsetpgrp<F: AsFd>(fd: F, pgrp: Pid) -> Result<()> { + let res = unsafe { libc::tcsetpgrp(fd.as_fd().as_raw_fd(), pgrp.into()) }; Errno::result(res).map(drop) } } @@ -404,7 +403,7 @@ pub fn getpgrp() -> Pid { /// /// 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"))] +#[cfg(linux_android)] #[inline] pub fn gettid() -> Pid { Pid(unsafe { libc::syscall(libc::SYS_gettid) as pid_t }) @@ -444,30 +443,22 @@ pub fn dup2(oldfd: RawFd, newfd: RawFd) -> Result<RawFd> { } /// 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)). +/// 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. +#[cfg(any( + netbsdlike, + solarish, + target_os = "freebsd", + target_os = "fuchsia", + target_os = "hurd", + target_os = "linux" +))] 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 res = unsafe { libc::dup3(oldfd, newfd, flags.bits()) }; - 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) + Errno::result(res) } /// Change the current working directory of the calling process (see @@ -583,8 +574,7 @@ pub fn mkfifo<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> { // mkfifoat is not implemented in OSX or android #[inline] #[cfg(not(any( - target_os = "macos", - target_os = "ios", + apple_targets, target_os = "haiku", target_os = "android", target_os = "redox" @@ -664,17 +654,17 @@ feature! { /// ``` #[inline] pub fn getcwd() -> Result<PathBuf> { - let mut buf = Vec::with_capacity(512); + let mut buf = Vec::<u8>::with_capacity(512); loop { unsafe { - let ptr = buf.as_mut_ptr() as *mut c_char; + let ptr = buf.as_mut_ptr().cast(); // 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) + let len = CStr::from_ptr(buf.as_ptr().cast()) .to_bytes() .len(); buf.set_len(len); @@ -688,8 +678,13 @@ pub fn getcwd() -> Result<PathBuf> { } } + #[cfg(not(target_os = "hurd"))] + const PATH_MAX: usize = libc::PATH_MAX as usize; + #[cfg(target_os = "hurd")] + const PATH_MAX: usize = 1024; // Hurd does not define a hard limit, so try a guess first + // Trigger the internal buffer resizing logic. - reserve_double_buffer_size(&mut buf, PATH_MAX as usize)?; + reserve_double_buffer_size(&mut buf, PATH_MAX)?; } } } @@ -749,11 +744,19 @@ pub fn fchown(fd: RawFd, owner: Option<Uid>, group: Option<Gid>) -> Result<()> { Errno::result(res).map(drop) } -/// Flags for `fchownat` function. -#[derive(Clone, Copy, Debug)] -pub enum FchownatFlags { - FollowSymlink, - NoFollowSymlink, +// Just a wrapper around `AtFlags` so that we can help our users migrate. +#[allow(missing_docs)] +#[cfg(not(target_os = "redox"))] +pub type FchownatFlags = AtFlags; +#[allow(missing_docs)] +#[cfg(not(target_os = "redox"))] +impl FchownatFlags { + #[deprecated(since = "0.28.0", note = "The variant is deprecated, please use `AtFlags` instead")] + #[allow(non_upper_case_globals)] + pub const FollowSymlink: FchownatFlags = FchownatFlags::empty(); + #[deprecated(since = "0.28.0", note = "The variant is deprecated, please use `AtFlags` instead")] + #[allow(non_upper_case_globals)] + pub const NoFollowSymlink: FchownatFlags = FchownatFlags::AT_SYMLINK_NOFOLLOW; } /// Change the ownership of the file at `path` to be owned by the specified @@ -767,10 +770,10 @@ pub enum FchownatFlags { /// 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, +/// If `flag` is `AtFlags::AT_SYMLINK_NOFOLLOW` 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 +/// `fchownat(None, path, owner, group, AtFlags::AT_SYMLINK_NOFOLLOW)` is identical to /// a call `libc::lchown(path, owner, group)`. That's why `lchown` is unimplemented in /// the `nix` crate. /// @@ -783,12 +786,8 @@ pub fn fchownat<P: ?Sized + NixPath>( path: &P, owner: Option<Uid>, group: Option<Gid>, - flag: FchownatFlags, + flag: AtFlags, ) -> 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( @@ -796,7 +795,7 @@ pub fn fchownat<P: ?Sized + NixPath>( cstr.as_ptr(), uid, gid, - atflag.bits() as libc::c_int, + flag.bits() ) })?; @@ -883,7 +882,7 @@ pub fn execvp<S: AsRef<CStr>>( /// 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"))] +#[cfg(any(target_os = "haiku", target_os = "hurd", target_os = "linux", target_os = "openbsd"))] pub fn execvpe<SA: AsRef<CStr>, SE: AsRef<CStr>>( filename: &CStr, args: &[SA], @@ -909,12 +908,7 @@ pub fn execvpe<SA: AsRef<CStr>, SE: AsRef<CStr>>( /// /// 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" -))] +#[cfg(any(linux_android, freebsdlike, target_os = "hurd"))] #[inline] pub fn fexecve<SA: AsRef<CStr>, SE: AsRef<CStr>>( fd: RawFd, @@ -939,15 +933,16 @@ pub fn fexecve<SA: AsRef<CStr>, SE: AsRef<CStr>>( /// /// 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"))] +#[cfg(linux_android)] #[inline] pub fn execveat<SA: AsRef<CStr>, SE: AsRef<CStr>>( - dirfd: RawFd, + dirfd: Option<RawFd>, pathname: &CStr, args: &[SA], env: &[SE], flags: super::fcntl::AtFlags, ) -> Result<Infallible> { + let dirfd = at_rawfd(dirfd); let args_p = to_exec_array(args); let env_p = to_exec_array(env); @@ -991,14 +986,10 @@ pub fn execveat<SA: AsRef<CStr>, SE: AsRef<CStr>>( /// * `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" + linux_android, + freebsdlike, + solarish, + netbsdlike ))] pub fn daemon(nochdir: bool, noclose: bool) -> Result<()> { let res = unsafe { libc::daemon(nochdir as c_int, noclose as c_int) }; @@ -1020,19 +1011,16 @@ feature! { 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 = "aix", - target_os = "solaris", ))] { + if #[cfg(any(freebsdlike, + solarish, + apple_targets, + target_os = "aix"))] { 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 ptr = name.as_ref().as_bytes().as_ptr().cast(); let len = name.as_ref().len() as sethostname_len_t; let res = unsafe { libc::sethostname(ptr, len) }; @@ -1056,14 +1044,14 @@ pub fn sethostname<S: AsRef<OsStr>>(name: S) -> Result<()> { 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 ptr = buffer.as_mut_ptr().cast(); 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(); + let len = CStr::from_ptr(buffer.as_ptr().cast()).len(); buffer.set_len(len); } OsString::from_vec(buffer) @@ -1105,9 +1093,8 @@ pub fn close(fd: RawFd) -> Result<()> { /// /// 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) - }; + let res = + unsafe { libc::read(fd, buf.as_mut_ptr().cast(), buf.len() as size_t) }; Errno::result(res).map(|r| r as usize) } @@ -1115,9 +1102,13 @@ pub fn read(fd: RawFd, buf: &mut [u8]) -> Result<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> { +pub fn write<Fd: AsFd>(fd: Fd, buf: &[u8]) -> Result<usize> { let res = unsafe { - libc::write(fd, buf.as_ptr() as *const c_void, buf.len() as size_t) + libc::write( + fd.as_fd().as_raw_fd(), + buf.as_ptr().cast(), + buf.len() as size_t, + ) }; Errno::result(res).map(|r| r as usize) @@ -1143,11 +1134,9 @@ pub enum Whence { /// 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", + freebsdlike, + solarish, target_os = "linux", - target_os = "solaris" ))] SeekData = libc::SEEK_DATA, /// Specify an offset relative to the next hole in the file greater than @@ -1156,11 +1145,9 @@ pub enum Whence { /// 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", + freebsdlike, + solarish, target_os = "linux", - target_os = "solaris" ))] SeekHole = libc::SEEK_HOLE, } @@ -1174,7 +1161,11 @@ pub fn lseek(fd: RawFd, offset: off_t, whence: Whence) -> Result<off_t> { Errno::result(res).map(|r| r as off_t) } -#[cfg(any(target_os = "linux", target_os = "android"))] +/// Move the read/write file offset. +/// +/// Unlike [`lseek`], it takes a 64-bit argument even on platforms where [`libc::off_t`] is +/// 32 bits. +#[cfg(linux_android)] pub fn lseek64( fd: RawFd, offset: libc::off64_t, @@ -1189,14 +1180,15 @@ pub fn lseek64( /// 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(); +pub fn pipe() -> std::result::Result<(OwnedFd, OwnedFd), Error> { + let mut fds = mem::MaybeUninit::<[OwnedFd; 2]>::uninit(); - let res = unsafe { libc::pipe(fds.as_mut_ptr() as *mut c_int) }; + let res = unsafe { libc::pipe(fds.as_mut_ptr().cast()) }; Error::result(res)?; - unsafe { Ok((fds.assume_init()[0], fds.assume_init()[1])) } + let [read, write] = unsafe { fds.assume_init() }; + Ok((read, write)) } feature! { @@ -1219,26 +1211,24 @@ feature! { /// /// See also [pipe(2)](https://man7.org/linux/man-pages/man2/pipe.2.html) #[cfg(any( - target_os = "android", - target_os = "dragonfly", + linux_android, + freebsdlike, + solarish, target_os = "emscripten", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", + target_os = "hurd", target_os = "redox", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris" + netbsdlike, ))] -pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> { - let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit(); +pub fn pipe2(flags: OFlag) -> Result<(OwnedFd, OwnedFd)> { + let mut fds = mem::MaybeUninit::<[OwnedFd; 2]>::uninit(); let res = - unsafe { libc::pipe2(fds.as_mut_ptr() as *mut c_int, flags.bits()) }; + unsafe { libc::pipe2(fds.as_mut_ptr().cast(), flags.bits()) }; Errno::result(res)?; - unsafe { Ok((fds.assume_init()[0], fds.assume_init()[1])) } + let [read, write] = unsafe { fds.assume_init() }; + Ok((read, write)) } /// Truncate a file to a specified length @@ -1261,6 +1251,7 @@ pub fn ftruncate<Fd: AsFd>(fd: Fd, len: off_t) -> Result<()> { Errno::result(unsafe { libc::ftruncate(fd.as_fd().as_raw_fd(), len) }).map(drop) } +/// Determines if the file descriptor refers to a valid terminal type device. pub fn isatty(fd: RawFd) -> Result<bool> { unsafe { // ENOTTY means `fd` is a valid file descriptor, but not a TTY, so @@ -1276,11 +1267,18 @@ pub fn isatty(fd: RawFd) -> Result<bool> { } } -/// Flags for `linkat` function. -#[derive(Clone, Copy, Debug)] -pub enum LinkatFlags { - SymlinkFollow, - NoSymlinkFollow, +#[allow(missing_docs)] +#[cfg(not(target_os = "redox"))] +pub type LinkatFlags = AtFlags; +#[allow(missing_docs)] +#[cfg(not(target_os = "redox"))] +impl LinkatFlags { + #[deprecated(since = "0.28.0", note = "The variant is deprecated, please use `AtFlags` instead")] + #[allow(non_upper_case_globals)] + pub const SymlinkFollow: LinkatFlags = LinkatFlags::AT_SYMLINK_FOLLOW; + #[deprecated(since = "0.28.0", note = "The variant is deprecated, please use `AtFlags` instead")] + #[allow(non_upper_case_globals)] + pub const NoSymlinkFollow: LinkatFlags = LinkatFlags::empty(); } /// Link one file to another file @@ -1288,7 +1286,7 @@ pub enum LinkatFlags { /// 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 +/// `newpath` and file descriptor `newdirfd`. In case `flag` is `AtFlags::AT_SYMLINK_FOLLOW` 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 @@ -1302,13 +1300,8 @@ pub fn linkat<P: ?Sized + NixPath>( oldpath: &P, newdirfd: Option<RawFd>, newpath: &P, - flag: LinkatFlags, + flag: AtFlags, ) -> 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( @@ -1316,7 +1309,7 @@ pub fn linkat<P: ?Sized + NixPath>( oldcstr.as_ptr(), at_rawfd(newdirfd), newcstr.as_ptr(), - atflag.bits() as libc::c_int, + flag.bits(), ) }) })??; @@ -1335,7 +1328,9 @@ pub fn unlink<P: ?Sized + NixPath>(path: &P) -> Result<()> { /// Flags for `unlinkat` function. #[derive(Clone, Copy, Debug)] pub enum UnlinkatFlags { + /// Remove the directory entry as a directory, not a normal file RemoveDir, + /// Remove the directory entry as a normal file, not a directory NoRemoveDir, } @@ -1369,6 +1364,7 @@ pub fn unlinkat<P: ?Sized + NixPath>( Errno::result(res).map(drop) } +/// Change a process's root directory #[inline] #[cfg(not(target_os = "fuchsia"))] pub fn chroot<P: ?Sized + NixPath>(path: &P) -> Result<()> { @@ -1381,13 +1377,7 @@ pub fn chroot<P: ?Sized + NixPath>(path: &P) -> Result<()> { /// 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" -))] +#[cfg(any(freebsdlike, linux_android, netbsdlike))] pub fn sync() { unsafe { libc::sync() }; } @@ -1396,7 +1386,7 @@ pub fn sync() { /// descriptor `fd` to disk /// /// See also [syncfs(2)](https://man7.org/linux/man-pages/man2/sync.2.html) -#[cfg(target_os = "linux")] +#[cfg(linux_android)] pub fn syncfs(fd: RawFd) -> Result<()> { let res = unsafe { libc::syncfs(fd) }; @@ -1418,15 +1408,12 @@ pub fn fsync(fd: RawFd) -> Result<()> { /// See also /// [fdatasync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html) #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "emscripten", + linux_android, + solarish, + netbsdlike, target_os = "freebsd", + target_os = "emscripten", target_os = "fuchsia", - target_os = "netbsd", - target_os = "openbsd", - target_os = "illumos", - target_os = "solaris" ))] #[inline] pub fn fdatasync(fd: RawFd) -> Result<()> { @@ -1527,7 +1514,7 @@ feature! { /// 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"))] +#[cfg(linux_android)] pub fn setfsuid(uid: Uid) -> Uid { let prev_fsuid = unsafe { libc::setfsuid(uid.into()) }; Uid::from_raw(prev_fsuid as uid_t) @@ -1538,7 +1525,7 @@ pub fn setfsuid(uid: Uid) -> Uid { /// 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"))] +#[cfg(linux_android)] pub fn setfsgid(gid: Gid) -> Gid { let prev_fsgid = unsafe { libc::setfsgid(gid.into()) }; Gid::from_raw(prev_fsgid as gid_t) @@ -1555,14 +1542,14 @@ feature! { /// **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")))] +#[cfg(not(apple_targets))] 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(), + Ok(None) | Err(_) => usize::MAX, }; // Next, get the number of groups so we can size our Vec @@ -1588,7 +1575,7 @@ pub fn getgroups() -> Result<Vec<Gid>> { let ngroups = unsafe { libc::getgroups( groups.capacity() as c_int, - groups.as_mut_ptr() as *mut gid_t, + groups.as_mut_ptr().cast(), ) }; @@ -1640,22 +1627,15 @@ pub fn getgroups() -> Result<Vec<Gid>> { /// # try_main().unwrap(); /// ``` #[cfg(not(any( - target_os = "ios", - target_os = "macos", + apple_targets, target_os = "redox", target_os = "haiku" )))] pub fn setgroups(groups: &[Gid]) -> Result<()> { cfg_if! { - if #[cfg(any(target_os = "aix", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris"))] { + if #[cfg(any(bsd, + solarish, + target_os = "aix"))] { type setgroups_ngroups_t = c_int; } else { type setgroups_ngroups_t = size_t; @@ -1667,7 +1647,7 @@ pub fn setgroups(groups: &[Gid]) -> Result<()> { let res = unsafe { libc::setgroups( groups.len() as setgroups_ngroups_t, - groups.as_ptr() as *const gid_t, + groups.as_ptr().cast(), ) }; @@ -1696,20 +1676,19 @@ pub fn setgroups(groups: &[Gid]) -> Result<()> { /// will only ever return the complete list or else an error. #[cfg(not(any( target_os = "aix", - target_os = "illumos", - target_os = "ios", - target_os = "macos", + solarish, + apple_targets, 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(), + Ok(None) | Err(_) => c_int::MAX, }; 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"))] { + if #[cfg(apple_targets)] { type getgrouplist_group_t = c_int; } else { type getgrouplist_group_t = gid_t; @@ -1722,7 +1701,7 @@ pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> { libc::getgrouplist( user.as_ptr(), gid as getgrouplist_group_t, - groups.as_mut_ptr() as *mut getgrouplist_group_t, + groups.as_mut_ptr().cast(), &mut ngroups, ) }; @@ -1781,14 +1760,13 @@ pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> { /// # try_main().unwrap(); /// ``` #[cfg(not(any( - target_os = "ios", - target_os = "macos", + apple_targets, 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"))] { + if #[cfg(apple_targets)] { type initgroups_group_t = c_int; } else { type initgroups_group_t = gid_t; @@ -1915,6 +1893,7 @@ pub fn sleep(seconds: c_uint) -> c_uint { feature! { #![feature = "acct"] +/// Process accounting #[cfg(not(any(target_os = "redox", target_os = "haiku")))] pub mod acct { use crate::errno::Errno; @@ -1970,7 +1949,7 @@ feature! { 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 p = path.as_mut_ptr().cast(); let fd = unsafe { libc::mkstemp(p) }; let last = path.pop(); // drop the trailing nul debug_assert!(last == Some(b'\0')); @@ -1983,6 +1962,38 @@ pub fn mkstemp<P: ?Sized + NixPath>(template: &P) -> Result<(RawFd, PathBuf)> { feature! { #![all(feature = "fs", feature = "feature")] +/// Creates a directory which persists even after process termination +/// +/// * `template`: a path whose rightmost characters contain some number of X, e.g. `/tmp/tmpdir_XXXXXX` +/// * returns: filename +/// +/// Err is returned either if no temporary filename could be created or the template had insufficient X +/// +/// See also [mkstemp(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdtemp.html) +/// +/// ``` +/// use nix::unistd; +/// +/// match unistd::mkdtemp("/tmp/tempdir_XXXXXX") { +/// Ok(_path) => { +/// // do something with directory +/// } +/// Err(e) => panic!("mkdtemp failed: {}", e) +/// }; +/// ``` +pub fn mkdtemp<P: ?Sized + NixPath>(template: &P) -> Result<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 p = unsafe { libc::mkdtemp(p) }; + if p.is_null() { + return Err(Errno::last()); + } + let last = path.pop(); // drop the trailing nul + debug_assert!(last == Some(b'\0')); + let pathname = OsString::from_vec(path); + Ok(PathBuf::from(pathname)) +} + /// Variable names for `pathconf` /// /// Nix uses the same naming convention for these variables as the @@ -2004,16 +2015,13 @@ feature! { #[non_exhaustive] pub enum PathconfVar { #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", + freebsdlike, + netbsdlike, 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, @@ -2035,86 +2043,62 @@ pub enum PathconfVar { /// a pipe. PIPE_BUF = libc::_PC_PIPE_BUF, #[cfg(any( - target_os = "android", + linux_android, + solarish, + netbsdlike, 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", + linux_android, + freebsdlike, 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", + freebsdlike, + linux_android, 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", + linux_android, + freebsdlike, 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", + linux_android, + freebsdlike, 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", + linux_android, + freebsdlike, 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", + linux_android, + freebsdlike, + solarish, + netbsdlike, 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 @@ -2128,50 +2112,36 @@ pub enum PathconfVar { /// 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", + linux_android, + freebsdlike, + solarish, 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", + linux_android, + freebsdlike, + solarish, 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", + linux_android, + freebsdlike, + solarish, + netbsdlike, 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, } @@ -2192,13 +2162,13 @@ pub enum PathconfVar { /// - `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>> { +pub fn fpathconf<F: AsFd>(fd: F, var: PathconfVar) -> Result<Option<c_long>> { let raw = unsafe { Errno::clear(); - libc::fpathconf(fd, var as c_int) + libc::fpathconf(fd.as_fd().as_raw_fd(), var as c_int) }; if raw == -1 { - if errno::errno() == 0 { + if Errno::last_raw() == 0 { Ok(None) } else { Err(Errno::last()) @@ -2238,7 +2208,7 @@ pub fn pathconf<P: ?Sized + NixPath>( libc::pathconf(cstr.as_ptr(), var as c_int) })?; if raw == -1 { - if errno::errno() == 0 { + if Errno::last_raw() == 0 { Ok(None) } else { Err(Errno::last()) @@ -2275,23 +2245,17 @@ 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", + linux_android, + freebsdlike, + apple_targets, 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, @@ -2299,68 +2263,47 @@ pub enum SysconfVar { 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. + /// The frequency of the statistics clock in 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())))] + #[cfg(any(bsd, solarish, target_os = "linux"))] /// 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"))] @@ -2369,308 +2312,176 @@ pub enum SysconfVar { 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", + freebsdlike, + apple_targets, 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())))] + #[cfg(any(bsd, solarish, target_os = "linux"))] /// 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())))] + #[cfg(any(bsd, solarish, target_os = "linux"))] /// 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())))] + #[cfg(any(bsd, solarish, target_os = "linux"))] /// 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", + freebsdlike, + apple_targets, + solarish, 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", + linux_android, + freebsdlike, + solarish, + apple_targets, 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", + freebsdlike, + solarish, + apple_targets, 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", + bsd, + solarish, 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", + linux_android, + freebsdlike, + apple_targets, 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", + bsd, + solarish, 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())))] + #[cfg(any(bsd, target_os = "linux",))] /// 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())))] + #[cfg(any(bsd, target_os = "linux",))] /// 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())))] + #[cfg(any(bsd, target_os = "linux",))] /// The implementation supports spin locks. _POSIX_SPIN_LOCKS = libc::_SC_SPIN_LOCKS, #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", + freebsdlike, + apple_targets, 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, + /// The number of replenishment operations that can be simultaneously pending for a particular + /// sporadic server scheduler. #[cfg(any( - target_os = "ios", + apple_targets, 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", + apple_targets, target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" + netbsdlike, ))] - #[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())))] + #[cfg(any(bsd, target_os = "linux"))] /// The implementation supports the Thread Process-Shared Synchronization /// option. _POSIX_THREAD_PROCESS_SHARED = libc::_SC_THREAD_PROCESS_SHARED, @@ -2679,7 +2490,6 @@ pub enum SysconfVar { 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( @@ -2687,484 +2497,319 @@ pub enum SysconfVar { 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", + freebsdlike, + apple_targets, 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", + freebsdlike, + apple_targets, 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", + freebsdlike, + apple_targets, 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", + freebsdlike, + apple_targets, 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, + /// Maximum size of a trace event name in characters. #[cfg(any( - target_os = "ios", + apple_targets, 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", + freebsdlike, + apple_targets, 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", + freebsdlike, + apple_targets, 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, + /// The length in bytes of a trace generation version string or a trace stream name. #[cfg(any( - target_os = "ios", + apple_targets, target_os = "linux", - target_os = "macos", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_TRACE_NAME_MAX = libc::_SC_TRACE_NAME_MAX, + /// Maximum number of times `posix_trace_create` may be called from the same or different + /// processes. #[cfg(any( - target_os = "ios", + apple_targets, target_os = "linux", - target_os = "macos", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_TRACE_SYS_MAX = libc::_SC_TRACE_SYS_MAX, + /// Maximum number of user trace event type identifiers for a single process. #[cfg(any( - target_os = "ios", + apple_targets, 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", + freebsdlike, + apple_targets, 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())))] + #[cfg(any(bsd, target_os = "linux"))] /// 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())))] + #[cfg(any(bsd, target_os = "linux"))] /// 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())))] + #[cfg(any(bsd, target_os = "linux"))] /// 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())))] + #[cfg(any(bsd, target_os = "linux"))] /// 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())))] + #[cfg(any(bsd, target_os = "linux"))] /// 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())))] + #[cfg(any(bsd, target_os = "linux"))] /// 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())))] + #[cfg(any(bsd, target_os = "linux"))] /// 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())))] + #[cfg(any(bsd, target_os = "linux"))] /// 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())))] + #[cfg(any(bsd, target_os = "linux"))] /// 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())))] + #[cfg(any(bsd, target_os = "linux"))] /// 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, + /// Maximum number of attempts made to destroy a thread's thread-specific data values on thread + /// exit. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] PTHREAD_DESTRUCTOR_ITERATIONS = libc::_SC_THREAD_DESTRUCTOR_ITERATIONS, + /// Maximum number of data keys that can be created by a process. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] PTHREAD_KEYS_MAX = libc::_SC_THREAD_KEYS_MAX, + /// Minimum size in bytes of thread stack storage. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] PTHREAD_STACK_MIN = libc::_SC_THREAD_STACK_MIN, + /// Maximum number of threads that can be created per process. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] PTHREAD_THREADS_MAX = libc::_SC_THREAD_THREADS_MAX, + /// The maximum number of repeated occurrences of a regular expression permitted when using + /// interval notation. #[cfg(not(target_os = "haiku"))] RE_DUP_MAX = libc::_SC_RE_DUP_MAX, + /// Maximum number of realtime signals reserved for application use. #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", + linux_android, + freebsdlike, + apple_targets, target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] RTSIG_MAX = libc::_SC_RTSIG_MAX, + /// Maximum number of semaphores that a process may have. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] SEM_NSEMS_MAX = libc::_SC_SEM_NSEMS_MAX, + /// The maximum value a semaphore may have. #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", + linux_android, + freebsdlike, + apple_targets, target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] SEM_VALUE_MAX = libc::_SC_SEM_VALUE_MAX, + /// Maximum number of queued signals that a process may send and have pending at the + /// receiver(s) at any time. #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", + linux_android, + freebsdlike, + apple_targets, target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] SIGQUEUE_MAX = libc::_SC_SIGQUEUE_MAX, + /// The minimum maximum number of streams that a process may have open at any one time. 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())))] + /// Maximum number of symbolic links that can be reliably traversed in the resolution of a + /// pathname in the absence of a loop. + #[cfg(any(bsd, target_os = "linux"))] SYMLOOP_MAX = libc::_SC_SYMLOOP_MAX, + /// Maximum number of timers per process supported. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] TIMER_MAX = libc::_SC_TIMER_MAX, + /// Maximum length of terminal device name. TTY_NAME_MAX = libc::_SC_TTY_NAME_MAX, + /// The minimum maximum number of types supported for the name of a timezone. 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", + linux_android, + freebsdlike, + apple_targets, 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", + linux_android, + freebsdlike, + apple_targets, 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", + linux_android, + freebsdlike, + apple_targets, target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports the XOpen Legacy Option group. + /// + /// See Also <https://pubs.opengroup.org/onlinepubs/007904975/basedefs/xbd_chap02.html> _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", + linux_android, + freebsdlike, + apple_targets, 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", + linux_android, + freebsdlike, + apple_targets, 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", + freebsdlike, + apple_targets, 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", + linux_android, + freebsdlike, + apple_targets, 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", + linux_android, + freebsdlike, + apple_targets, 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"))] + #[cfg(linux_android)] _PHYS_PAGES = libc::_SC_PHYS_PAGES, /// The number of currently available pages of physical memory. - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] _AVPHYS_PAGES = libc::_SC_AVPHYS_PAGES, /// The number of processors configured. - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] _NPROCESSORS_CONF = libc::_SC_NPROCESSORS_CONF, /// The number of processors currently online (available). - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] _NPROCESSORS_ONLN = libc::_SC_NPROCESSORS_ONLN, } @@ -3190,7 +2835,7 @@ pub fn sysconf(var: SysconfVar) -> Result<Option<c_long>> { libc::sysconf(var as c_int) }; if raw == -1 { - if errno::errno() == 0 { + if Errno::last_raw() == 0 { Ok(None) } else { Err(Errno::last()) @@ -3201,12 +2846,15 @@ pub fn sysconf(var: SysconfVar) -> Result<Option<c_long>> { } } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[cfg(feature = "fs")] mod pivot_root { use crate::errno::Errno; use crate::{NixPath, Result}; + /// Change the root file system. + /// + /// See Also [`pivot_root`](https://man7.org/linux/man-pages/man2/pivot_root.2.html) pub fn pivot_root<P1: ?Sized + NixPath, P2: ?Sized + NixPath>( new_root: &P1, put_old: &P2, @@ -3225,13 +2873,7 @@ mod pivot_root { } } -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd" -))] +#[cfg(any(linux_android, freebsdlike, target_os = "openbsd"))] mod setres { feature! { #![feature = "user"] @@ -3276,13 +2918,7 @@ mod setres { } } -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd" -))] +#[cfg(any(linux_android, freebsdlike, target_os = "openbsd"))] mod getres { feature! { #![feature = "user"] @@ -3294,16 +2930,22 @@ mod getres { /// Real, effective and saved user IDs. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct ResUid { + /// Real UID pub real: Uid, + /// Effective UID pub effective: Uid, + /// Saved UID pub saved: Uid, } /// Real, effective and saved group IDs. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct ResGid { + /// Real GID pub real: Gid, + /// Effective GID pub effective: Gid, + /// Saved GID pub saved: Gid, } @@ -3318,9 +2960,9 @@ mod getres { /// #[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 mut ruid = libc::uid_t::MAX; + let mut euid = libc::uid_t::MAX; + let mut suid = libc::uid_t::MAX; let res = unsafe { libc::getresuid(&mut ruid, &mut euid, &mut suid) }; Errno::result(res).map(|_| ResUid { @@ -3341,9 +2983,9 @@ mod getres { /// #[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 mut rgid = libc::gid_t::MAX; + let mut egid = libc::gid_t::MAX; + let mut sgid = libc::gid_t::MAX; let res = unsafe { libc::getresgid(&mut rgid, &mut egid, &mut sgid) }; Errno::result(res).map(|_| ResGid { @@ -3355,6 +2997,62 @@ mod getres { } } +#[cfg(feature = "process")] +#[cfg(target_os = "freebsd")] +libc_bitflags! { + /// Flags for [`rfork`] + /// + /// subset of flags supported by FreeBSD 12.x and onwards + /// with a safe outcome, thus as `RFMEM` can possibly lead to undefined behavior, + /// it is not in the list. And `rfork_thread` is deprecated. + pub struct RforkFlags: libc::c_int { + /// creates a new process. + RFPROC; + /// the child process will detach from the parent. + /// however, no status will be emitted at child's exit. + RFNOWAIT; + /// the file descriptor's table will be copied + RFFDG; + /// a new file descriptor's table will be created + RFCFDG; + /// force sharing the sigacts structure between + /// the child and the parent. + RFSIGSHARE; + /// enables kernel thread support. + RFTHREAD; + /// sets a status to emit at child's exit. + RFTSIGZMB; + /// linux's behavior compatibility setting. + /// emits SIGUSR1 as opposed to SIGCHLD upon child's exit. + RFLINUXTHPN; + } +} + +feature! { +#![feature = "process"] +#[cfg(target_os = "freebsd")] +/// Like [`fork`], `rfork` can be used to have a tigher control about which +/// resources child and parent process will be sharing, file descriptors, +/// address spaces and child exit's behavior. +/// +/// # Safety +/// +/// The same restrictions apply as for [`fork`]. +/// +/// # See Also +/// +/// * [rfork(2)](https://man.freebsd.org/cgi/man.cgi?query=rfork) +pub unsafe fn rfork(flags: RforkFlags) -> Result<ForkResult> { + use ForkResult::*; + let res = unsafe { libc::rfork(flags.bits()) }; + + Errno::result(res).map(|res| match res { + 0 => Child, + res => Parent { child: Pid(res) }, + }) +} +} + #[cfg(feature = "fs")] libc_bitflags! { /// Options for access() @@ -3419,9 +3117,8 @@ pub fn faccessat<P: ?Sized + NixPath>( /// * [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( + freebsdlike, 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 { @@ -3460,39 +3157,33 @@ pub struct User { pub shell: PathBuf, /// Login class #[cfg(not(any( + linux_android, + solarish, target_os = "aix", - target_os = "android", target_os = "fuchsia", target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris" + target_os = "hurd", )))] - #[cfg_attr(docsrs, doc(cfg(all())))] pub class: CString, /// Last password change #[cfg(not(any( + linux_android, + solarish, target_os = "aix", - target_os = "android", target_os = "fuchsia", target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris" + target_os = "hurd", )))] - #[cfg_attr(docsrs, doc(cfg(all())))] pub change: libc::time_t, /// Expiration time of account #[cfg(not(any( + linux_android, + solarish, target_os = "aix", - target_os = "android", target_os = "fuchsia", target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris" + target_os = "hurd", )))] - #[cfg_attr(docsrs, doc(cfg(all())))] pub expire: libc::time_t, } @@ -3539,34 +3230,31 @@ impl From<&libc::passwd> for User { uid: Uid::from_raw(pw.pw_uid), gid: Gid::from_raw(pw.pw_gid), #[cfg(not(any( + linux_android, + solarish, target_os = "aix", - target_os = "android", target_os = "fuchsia", target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris" + target_os = "hurd", )))] class: CString::new(CStr::from_ptr(pw.pw_class).to_bytes()) .unwrap(), #[cfg(not(any( + linux_android, + solarish, target_os = "aix", - target_os = "android", target_os = "fuchsia", target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris" + target_os = "hurd", )))] change: pw.pw_change, #[cfg(not(any( + linux_android, + solarish, target_os = "aix", - target_os = "android", target_os = "fuchsia", target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris" + target_os = "hurd", )))] expire: pw.pw_expire, } @@ -3602,40 +3290,37 @@ impl From<User> for libc::passwd { pw_uid: u.uid.0, pw_gid: u.gid.0, #[cfg(not(any( + linux_android, + solarish, target_os = "aix", - target_os = "android", target_os = "fuchsia", target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris" + target_os = "hurd", )))] pw_class: u.class.into_raw(), #[cfg(not(any( + linux_android, + solarish, target_os = "aix", - target_os = "android", target_os = "fuchsia", target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris" + target_os = "hurd", )))] pw_change: u.change, #[cfg(not(any( + linux_android, + solarish, target_os = "aix", - target_os = "android", target_os = "fuchsia", target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris" + target_os = "hurd", )))] pw_expire: u.expire, - #[cfg(target_os = "illumos")] + #[cfg(solarish)] pw_age: CString::new("").unwrap().into_raw(), - #[cfg(target_os = "illumos")] + #[cfg(solarish)] pw_comment: CString::new("").unwrap().into_raw(), - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg(freebsdlike)] pw_fields: 0, } } @@ -3680,7 +3365,7 @@ impl User { } else { // SAFETY: `f` guarantees that `pwd` is initialized if `res` // is not null. - let pwd = pwd.assume_init(); + let pwd = unsafe { pwd.assume_init() }; return Ok(Some(User::from(&pwd))); } } else if Errno::last() == Errno::ERANGE { @@ -3790,18 +3475,17 @@ impl Group { let mut ret = Vec::new(); for i in 0.. { - let u = mem.offset(i); - if (*u).is_null() { + let u = unsafe { mem.offset(i).read_unaligned() }; + if u.is_null() { break; } else { - let s = CStr::from_ptr(*u).to_string_lossy().into_owned(); + let s = unsafe {CStr::from_ptr(u).to_string_lossy().into_owned()}; ret.push(s); } } ret } - /// # Safety /// /// If `f` writes to its `*mut *mut libc::group` parameter, then it must @@ -3839,7 +3523,7 @@ impl Group { } else { // SAFETY: `f` guarantees that `grp` is initialized if `res` // is not null. - let grp = grp.assume_init(); + let grp = unsafe { grp.assume_init() }; return Ok(Some(Group::from(&grp))); } } else if Errno::last() == Errno::ERANGE { @@ -3913,19 +3597,22 @@ feature! { /// 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> { +pub fn ttyname<F: AsFd>(fd: F) -> Result<PathBuf> { + #[cfg(not(target_os = "hurd"))] const PATH_MAX: usize = libc::PATH_MAX as usize; + #[cfg(target_os = "hurd")] + const PATH_MAX: usize = 1024; // Hurd does not define a hard limit, so try a guess first let mut buf = vec![0_u8; PATH_MAX]; - let c_buf = buf.as_mut_ptr() as *mut libc::c_char; + let c_buf = buf.as_mut_ptr().cast(); - let ret = unsafe { libc::ttyname_r(fd, c_buf, buf.len()) }; + let ret = unsafe { libc::ttyname_r(fd.as_fd().as_raw_fd(), c_buf, buf.len()) }; if ret != 0 { - return Err(Errno::from_i32(ret)); + return Err(Errno::from_raw(ret)); } - let nul = buf.iter().position(|c| *c == b'\0').unwrap(); - buf.truncate(nul); - Ok(OsString::from_vec(buf).into()) + CStr::from_bytes_until_nul(&buf[..]) + .map(|s| OsStr::from_bytes(s.to_bytes()).into()) + .map_err(|_| Errno::EINVAL) } } @@ -3935,19 +3622,12 @@ feature! { /// 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)> { +#[cfg(bsd)] +pub fn getpeereid<F: AsFd>(fd: F) -> Result<(Uid, Gid)> { let mut uid = 1; let mut gid = 1; - let ret = unsafe { libc::getpeereid(fd, &mut uid, &mut gid) }; + let ret = unsafe { libc::getpeereid(fd.as_fd().as_raw_fd(), &mut uid, &mut gid) }; Errno::result(ret).map(|_| (Uid(uid), Gid(gid))) } @@ -3959,14 +3639,7 @@ feature! { /// 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" -))] +#[cfg(bsd)] 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()) diff --git a/third_party/rust/nix/test/common/mod.rs b/third_party/rust/nix/test/common/mod.rs index bb056aab87..db4aed2598 100644 --- a/third_party/rust/nix/test/common/mod.rs +++ b/third_party/rust/nix/test/common/mod.rs @@ -2,18 +2,18 @@ use cfg_if::cfg_if; #[macro_export] macro_rules! skip { - ($($reason: expr),+) => { + ($($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"))] { + if #[cfg(linux_android)] { #[macro_export] macro_rules! require_capability { ($name:expr, $capname:ident) => { use ::caps::{Capability, CapSet, has_cap}; @@ -51,7 +51,7 @@ macro_rules! require_mount { }; } -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[macro_export] macro_rules! skip_if_cirrus { ($reason:expr) => { @@ -87,7 +87,7 @@ macro_rules! skip_if_not_root { } cfg_if! { - if #[cfg(any(target_os = "android", target_os = "linux"))] { + if #[cfg(linux_android)] { #[macro_export] macro_rules! skip_if_seccomp { ($name:expr) => { if let Ok(s) = std::fs::read_to_string("/proc/self/status") { diff --git a/third_party/rust/nix/test/sys/mod.rs b/third_party/rust/nix/test/sys/mod.rs index 20312120a6..fb3f6be0e5 100644 --- a/third_party/rust/nix/test/sys/mod.rs +++ b/third_party/rust/nix/test/sys/mod.rs @@ -7,16 +7,16 @@ mod test_signal; // cases on DragonFly. #[cfg(any( target_os = "freebsd", - target_os = "ios", + apple_targets, 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" + target_os = "haiku", + target_os = "hurd" )))] mod test_ioctl; #[cfg(not(target_os = "redox"))] @@ -30,7 +30,7 @@ mod test_socket; #[cfg(not(any(target_os = "redox")))] mod test_sockopt; mod test_stat; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] mod test_sysinfo; #[cfg(not(any( target_os = "redox", @@ -41,20 +41,44 @@ mod test_termios; mod test_uio; mod test_wait; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] mod test_epoll; #[cfg(target_os = "linux")] +mod test_fanotify; +#[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" -))] + +#[cfg(any(linux_android, freebsdlike, netbsdlike, apple_targets))] mod test_ptrace; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] mod test_timerfd; + +#[cfg(all( + any( + target_os = "freebsd", + solarish, + target_os = "linux", + target_os = "netbsd" + ), + feature = "time", + feature = "signal" +))] +mod test_timer; + +#[cfg(bsd)] +mod test_event; +mod test_statvfs; +mod test_time; +mod test_utsname; + +#[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "openbsd"))] +mod test_statfs; + +#[cfg(not(any( + target_os = "redox", + target_os = "fuchsia", + solarish, + target_os = "haiku" +)))] +mod test_resource; diff --git a/third_party/rust/nix/test/sys/test_aio.rs b/third_party/rust/nix/test/sys/test_aio.rs index 5035b5a08f..ba5ad02ec3 100644 --- a/third_party/rust/nix/test/sys/test_aio.rs +++ b/third_party/rust/nix/test/sys/test_aio.rs @@ -67,7 +67,7 @@ mod aio_fsync { // Skip on Linux, because Linux's AIO implementation can't detect errors // synchronously #[test] - #[cfg(any(target_os = "freebsd", target_os = "macos"))] + #[cfg(any(target_os = "freebsd", apple_targets))] fn error() { use std::mem; @@ -157,7 +157,7 @@ mod aio_read { // Skip on Linux, because Linux's AIO implementation can't detect errors // synchronously #[test] - #[cfg(any(target_os = "freebsd", target_os = "macos"))] + #[cfg(any(target_os = "freebsd", apple_targets))] fn error() { const INITIAL: &[u8] = b"abcdef123456"; let mut rbuf = vec![0; 4]; @@ -411,7 +411,7 @@ mod aio_write { // Skip on Linux, because Linux's AIO implementation can't detect errors // synchronously #[test] - #[cfg(any(target_os = "freebsd", target_os = "macos"))] + #[cfg(any(target_os = "freebsd", apple_targets))] fn error() { let wbuf = "CDEF".to_string().into_bytes(); let mut aiow = Box::pin(AioWrite::new( @@ -498,7 +498,9 @@ mod aio_writev { any( all(target_env = "musl", target_arch = "x86_64"), target_arch = "mips", - target_arch = "mips64" + target_arch = "mips32r6", + target_arch = "mips64", + target_arch = "mips64r6" ), ignore )] @@ -567,12 +569,6 @@ fn test_aio_cancel_all() { } #[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"; @@ -622,3 +618,53 @@ fn test_aio_suspend() { assert_eq!(wcb.as_mut().aio_return().unwrap(), WBUF.len()); assert_eq!(rcb.as_mut().aio_return().unwrap(), rlen); } + +/// 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() { + use std::io::{IoSlice, IoSliceMut}; + + 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/third_party/rust/nix/test/sys/test_aio_drop.rs b/third_party/rust/nix/test/sys/test_aio_drop.rs index bbe6623fd7..54106dd168 100644 --- a/third_party/rust/nix/test/sys/test_aio_drop.rs +++ b/third_party/rust/nix/test/sys/test_aio_drop.rs @@ -8,8 +8,7 @@ not(target_env = "uclibc"), any( target_os = "linux", - target_os = "ios", - target_os = "macos", + apple_targets, target_os = "freebsd", target_os = "netbsd" ) diff --git a/third_party/rust/nix/test/sys/test_event.rs b/third_party/rust/nix/test/sys/test_event.rs new file mode 100644 index 0000000000..a10b1e5d12 --- /dev/null +++ b/third_party/rust/nix/test/sys/test_event.rs @@ -0,0 +1,41 @@ +use libc::intptr_t; +use nix::sys::event::{EventFilter, EventFlag, FilterFlag, KEvent}; + +#[test] +fn test_struct_kevent() { + use std::mem; + + let udata: intptr_t = 12345; + let data: intptr_t = 0x1337; + + let actual = KEvent::new( + 0xdead_beef, + EventFilter::EVFILT_READ, + EventFlag::EV_ONESHOT | EventFlag::EV_ADD, + FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT, + data, + udata, + ); + assert_eq!(0xdead_beef, actual.ident()); + assert_eq!(EventFilter::EVFILT_READ, actual.filter().unwrap()); + assert_eq!(libc::EV_ONESHOT | libc::EV_ADD, actual.flags().bits()); + assert_eq!(libc::NOTE_CHILD | libc::NOTE_EXIT, actual.fflags().bits()); + assert_eq!(data, actual.data()); + assert_eq!(udata, actual.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/third_party/rust/nix/test/sys/test_fanotify.rs b/third_party/rust/nix/test/sys/test_fanotify.rs new file mode 100644 index 0000000000..20226c272a --- /dev/null +++ b/third_party/rust/nix/test/sys/test_fanotify.rs @@ -0,0 +1,149 @@ +use crate::*; +use nix::sys::fanotify::{ + EventFFlags, Fanotify, FanotifyResponse, InitFlags, MarkFlags, MaskFlags, + Response, +}; +use std::fs::{read_link, File, OpenOptions}; +use std::io::ErrorKind; +use std::io::{Read, Write}; +use std::os::fd::AsRawFd; +use std::thread; + +#[test] +/// Run fanotify tests sequentially to avoid tmp files races +pub fn test_fanotify() { + require_capability!("test_fanotify", CAP_SYS_ADMIN); + + test_fanotify_notifications(); + test_fanotify_responses(); +} + +fn test_fanotify_notifications() { + let group = + Fanotify::init(InitFlags::FAN_CLASS_NOTIF, EventFFlags::O_RDONLY) + .unwrap(); + let tempdir = tempfile::tempdir().unwrap(); + let tempfile = tempdir.path().join("test"); + OpenOptions::new() + .write(true) + .create_new(true) + .open(&tempfile) + .unwrap(); + + group + .mark( + MarkFlags::FAN_MARK_ADD, + MaskFlags::FAN_OPEN | MaskFlags::FAN_MODIFY | MaskFlags::FAN_CLOSE, + None, + Some(&tempfile), + ) + .unwrap(); + + // modify test file + { + let mut f = OpenOptions::new().write(true).open(&tempfile).unwrap(); + f.write_all(b"hello").unwrap(); + } + + let mut events = group.read_events().unwrap(); + assert_eq!(events.len(), 1, "should have read exactly one event"); + let event = events.pop().unwrap(); + assert!(event.check_version()); + assert_eq!( + event.mask(), + MaskFlags::FAN_OPEN + | MaskFlags::FAN_MODIFY + | MaskFlags::FAN_CLOSE_WRITE + ); + let fd_opt = event.fd(); + let fd = fd_opt.as_ref().unwrap(); + let path = read_link(format!("/proc/self/fd/{}", fd.as_raw_fd())).unwrap(); + assert_eq!(path, tempfile); + + // read test file + { + let mut f = File::open(&tempfile).unwrap(); + let mut s = String::new(); + f.read_to_string(&mut s).unwrap(); + } + + let mut events = group.read_events().unwrap(); + assert_eq!(events.len(), 1, "should have read exactly one event"); + let event = events.pop().unwrap(); + assert!(event.check_version()); + assert_eq!( + event.mask(), + MaskFlags::FAN_OPEN | MaskFlags::FAN_CLOSE_NOWRITE + ); + let fd_opt = event.fd(); + let fd = fd_opt.as_ref().unwrap(); + let path = read_link(format!("/proc/self/fd/{}", fd.as_raw_fd())).unwrap(); + assert_eq!(path, tempfile); +} + +fn test_fanotify_responses() { + let group = + Fanotify::init(InitFlags::FAN_CLASS_CONTENT, EventFFlags::O_RDONLY) + .unwrap(); + let tempdir = tempfile::tempdir().unwrap(); + let tempfile = tempdir.path().join("test"); + OpenOptions::new() + .write(true) + .create_new(true) + .open(&tempfile) + .unwrap(); + + group + .mark( + MarkFlags::FAN_MARK_ADD, + MaskFlags::FAN_OPEN_PERM, + None, + Some(&tempfile), + ) + .unwrap(); + + let file_thread = thread::spawn({ + let tempfile = tempfile.clone(); + + move || { + // first open, should fail + let Err(e) = File::open(&tempfile) else { + panic!("The first open should fail"); + }; + assert_eq!(e.kind(), ErrorKind::PermissionDenied); + + // second open, should succeed + File::open(&tempfile).unwrap(); + } + }); + + // Deny the first open try + let mut events = group.read_events().unwrap(); + assert_eq!(events.len(), 1, "should have read exactly one event"); + let event = events.pop().unwrap(); + assert!(event.check_version()); + assert_eq!(event.mask(), MaskFlags::FAN_OPEN_PERM); + let fd_opt = event.fd(); + let fd = fd_opt.as_ref().unwrap(); + let path = read_link(format!("/proc/self/fd/{}", fd.as_raw_fd())).unwrap(); + assert_eq!(path, tempfile); + group + .write_response(FanotifyResponse::new(*fd, Response::FAN_DENY)) + .unwrap(); + + // Allow the second open try + let mut events = group.read_events().unwrap(); + assert_eq!(events.len(), 1, "should have read exactly one event"); + let event = events.pop().unwrap(); + assert!(event.check_version()); + assert_eq!(event.mask(), MaskFlags::FAN_OPEN_PERM); + let fd_opt = event.fd(); + let fd = fd_opt.as_ref().unwrap(); + let path = read_link(format!("/proc/self/fd/{}", fd.as_raw_fd())).unwrap(); + assert_eq!(path, tempfile); + group + .write_response(FanotifyResponse::new(*fd, Response::FAN_ALLOW)) + .unwrap(); + + file_thread.join().unwrap(); +} diff --git a/third_party/rust/nix/test/sys/test_ioctl.rs b/third_party/rust/nix/test/sys/test_ioctl.rs index 40f60cfdbc..08843bf61c 100644 --- a/third_party/rust/nix/test/sys/test_ioctl.rs +++ b/third_party/rust/nix/test/sys/test_ioctl.rs @@ -28,7 +28,7 @@ ioctl_readwrite_buf!(readwritebuf_test, 0, 0, u32); // 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"))] +#[cfg(linux_android)] mod linux { // The cast is not unnecessary on all platforms. #[allow(clippy::unnecessary_cast)] @@ -36,7 +36,9 @@ mod linux { fn test_op_none() { if cfg!(any( target_arch = "mips", + target_arch = "mips32r6", target_arch = "mips64", + target_arch = "mips64r6", target_arch = "powerpc", target_arch = "powerpc64" )) { @@ -54,7 +56,9 @@ mod linux { fn test_op_write() { if cfg!(any( target_arch = "mips", + target_arch = "mips32r6", target_arch = "mips64", + target_arch = "mips64r6", target_arch = "powerpc", target_arch = "powerpc64" )) { @@ -69,7 +73,11 @@ mod linux { #[cfg(target_pointer_width = "64")] #[test] fn test_op_write_64() { - if cfg!(any(target_arch = "mips64", target_arch = "powerpc64")) { + if cfg!(any( + target_arch = "mips64", + target_arch = "mips64r6", + target_arch = "powerpc64" + )) { assert_eq!( request_code_write!(b'z', 10, 1u64 << 32) as u32, 0x8000_7A0A @@ -88,7 +96,9 @@ mod linux { fn test_op_read() { if cfg!(any( target_arch = "mips", + target_arch = "mips32r6", target_arch = "mips64", + target_arch = "mips64r6", target_arch = "powerpc", target_arch = "powerpc64" )) { @@ -103,7 +113,11 @@ mod linux { #[cfg(target_pointer_width = "64")] #[test] fn test_op_read_64() { - if cfg!(any(target_arch = "mips64", target_arch = "powerpc64")) { + if cfg!(any( + target_arch = "mips64", + target_arch = "mips64r6", + target_arch = "powerpc64" + )) { assert_eq!( request_code_read!(b'z', 10, 1u64 << 32) as u32, 0x4000_7A0A @@ -134,14 +148,7 @@ mod linux { } } -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" -))] +#[cfg(bsd)] mod bsd { #[test] fn test_op_none() { @@ -149,7 +156,7 @@ mod bsd { assert_eq!(request_code_none!(b'a', 255), 0x2000_61FF); } - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg(freebsdlike)] #[test] fn test_op_write_int() { assert_eq!(request_code_write_int!(b'v', 4), 0x2004_7604); @@ -193,7 +200,7 @@ mod bsd { } } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] mod linux_ioctls { use std::mem; use std::os::unix::io::AsRawFd; diff --git a/third_party/rust/nix/test/sys/test_mman.rs b/third_party/rust/nix/test/sys/test_mman.rs index b4674e53fa..3689f642be 100644 --- a/third_party/rust/nix/test/sys/test_mman.rs +++ b/third_party/rust/nix/test/sys/test_mman.rs @@ -1,44 +1,44 @@ -use nix::sys::mman::{mmap, MapFlags, ProtFlags}; -use std::{num::NonZeroUsize, os::unix::io::BorrowedFd}; +#![allow(clippy::redundant_slicing)] + +use nix::sys::mman::{mmap_anonymous, MapFlags, ProtFlags}; +use std::num::NonZeroUsize; #[test] fn test_mmap_anonymous() { unsafe { - let ptr = mmap::<BorrowedFd>( + let mut ptr = mmap_anonymous( None, NonZeroUsize::new(1).unwrap(), ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, - MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS, - None, - 0, + MapFlags::MAP_PRIVATE, ) - .unwrap() as *mut u8; - assert_eq!(*ptr, 0x00u8); - *ptr = 0xffu8; - assert_eq!(*ptr, 0xffu8); + .unwrap() + .cast::<u8>(); + assert_eq!(*ptr.as_ref(), 0x00u8); + *ptr.as_mut() = 0xffu8; + assert_eq!(*ptr.as_ref(), 0xffu8); } } #[test] #[cfg(any(target_os = "linux", target_os = "netbsd"))] fn test_mremap_grow() { - use nix::libc::{c_void, size_t}; + use nix::libc::size_t; use nix::sys::mman::{mremap, MRemapFlags}; + use std::ptr::NonNull; const ONE_K: size_t = 1024; let one_k_non_zero = NonZeroUsize::new(ONE_K).unwrap(); let slice: &mut [u8] = unsafe { - let mem = mmap::<BorrowedFd>( + let mem = mmap_anonymous( None, one_k_non_zero, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, - MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, - None, - 0, + MapFlags::MAP_PRIVATE, ) .unwrap(); - std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K) + std::slice::from_raw_parts_mut(mem.as_ptr().cast(), ONE_K) }; assert_eq!(slice[ONE_K - 1], 0x00); slice[ONE_K - 1] = 0xFF; @@ -47,7 +47,7 @@ fn test_mremap_grow() { let slice: &mut [u8] = unsafe { #[cfg(target_os = "linux")] let mem = mremap( - slice.as_mut_ptr() as *mut c_void, + NonNull::from(&mut slice[..]).cast(), ONE_K, 10 * ONE_K, MRemapFlags::MREMAP_MAYMOVE, @@ -56,14 +56,14 @@ fn test_mremap_grow() { .unwrap(); #[cfg(target_os = "netbsd")] let mem = mremap( - slice.as_mut_ptr() as *mut c_void, + NonNull::from(&mut slice[..]).cast(), ONE_K, 10 * ONE_K, MRemapFlags::MAP_REMAPDUP, None, ) .unwrap(); - std::slice::from_raw_parts_mut(mem as *mut u8, 10 * ONE_K) + std::slice::from_raw_parts_mut(mem.cast().as_ptr(), 10 * ONE_K) }; // The first KB should still have the old data in it. @@ -80,23 +80,22 @@ fn test_mremap_grow() { // 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::libc::size_t; use nix::sys::mman::{mremap, MRemapFlags}; use std::num::NonZeroUsize; + use std::ptr::NonNull; const ONE_K: size_t = 1024; let ten_one_k = NonZeroUsize::new(10 * ONE_K).unwrap(); let slice: &mut [u8] = unsafe { - let mem = mmap::<BorrowedFd>( + let mem = mmap_anonymous( None, ten_one_k, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, - MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, - None, - 0, + MapFlags::MAP_PRIVATE, ) .unwrap(); - std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K) + std::slice::from_raw_parts_mut(mem.as_ptr().cast(), ONE_K) }; assert_eq!(slice[ONE_K - 1], 0x00); slice[ONE_K - 1] = 0xFF; @@ -104,7 +103,7 @@ fn test_mremap_shrink() { let slice: &mut [u8] = unsafe { let mem = mremap( - slice.as_mut_ptr() as *mut c_void, + NonNull::from(&mut slice[..]).cast(), ten_one_k.into(), ONE_K, MRemapFlags::empty(), @@ -113,8 +112,8 @@ fn test_mremap_shrink() { .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) + assert_eq!(mem.as_ptr(), NonNull::from(&mut slice[..]).cast().as_ptr()); + std::slice::from_raw_parts_mut(mem.as_ptr().cast(), ONE_K) }; // The first KB should still be accessible and have the old data in it. diff --git a/third_party/rust/nix/test/sys/test_ptrace.rs b/third_party/rust/nix/test/sys/test_ptrace.rs index 530560fe17..246b35445d 100644 --- a/third_party/rust/nix/test/sys/test_ptrace.rs +++ b/third_party/rust/nix/test/sys/test_ptrace.rs @@ -6,11 +6,11 @@ use memoffset::offset_of; use nix::errno::Errno; use nix::sys::ptrace; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] use nix::sys::ptrace::Options; use nix::unistd::getpid; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] use std::mem; use crate::*; @@ -28,7 +28,7 @@ fn test_ptrace() { // Just make sure ptrace_setoptions can be called at all, for now. #[test] -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] fn test_ptrace_setoptions() { require_capability!("test_ptrace_setoptions", CAP_SYS_PTRACE); let err = ptrace::setoptions(getpid(), Options::PTRACE_O_TRACESYSGOOD) @@ -38,7 +38,7 @@ fn test_ptrace_setoptions() { // Just make sure ptrace_getevent can be called at all, for now. #[test] -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] fn test_ptrace_getevent() { require_capability!("test_ptrace_getevent", CAP_SYS_PTRACE); let err = ptrace::getevent(getpid()).unwrap_err(); @@ -47,7 +47,7 @@ fn test_ptrace_getevent() { // Just make sure ptrace_getsiginfo can be called at all, for now. #[test] -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] fn test_ptrace_getsiginfo() { require_capability!("test_ptrace_getsiginfo", CAP_SYS_PTRACE); if let Err(Errno::EOPNOTSUPP) = ptrace::getsiginfo(getpid()) { @@ -57,7 +57,7 @@ fn test_ptrace_getsiginfo() { // Just make sure ptrace_setsiginfo can be called at all, for now. #[test] -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] fn test_ptrace_setsiginfo() { require_capability!("test_ptrace_setsiginfo", CAP_SYS_PTRACE); let siginfo = unsafe { mem::zeroed() }; diff --git a/third_party/rust/nix/test/test_resource.rs b/third_party/rust/nix/test/sys/test_resource.rs index 2ab581ba29..8b12a9495b 100644 --- a/third_party/rust/nix/test/test_resource.rs +++ b/third_party/rust/nix/test/sys/test_resource.rs @@ -1,10 +1,5 @@ -#[cfg(not(any( - target_os = "redox", - target_os = "fuchsia", - target_os = "illumos", - target_os = "haiku" -)))] use nix::sys::resource::{getrlimit, setrlimit, Resource}; +use nix::sys::resource::{getrusage, UsageWho}; /// 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 @@ -15,12 +10,6 @@ use nix::sys::resource::{getrlimit, setrlimit, Resource}; /// 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(); @@ -32,3 +21,23 @@ pub fn test_resource_limits_nofile() { let (new_soft_limit, _) = getrlimit(Resource::RLIMIT_NOFILE).unwrap(); assert_eq!(new_soft_limit, soft_limit); } + +#[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/third_party/rust/nix/test/sys/test_select.rs b/third_party/rust/nix/test/sys/test_select.rs index 79f75de3b4..e39a31923a 100644 --- a/third_party/rust/nix/test/sys/test_select.rs +++ b/third_party/rust/nix/test/sys/test_select.rs @@ -1,22 +1,20 @@ use nix::sys::select::*; use nix::sys::signal::SigSet; -use nix::sys::time::{TimeSpec, TimeValLike}; +use nix::sys::time::{TimeSpec, TimeVal, TimeValLike}; use nix::unistd::{pipe, write}; -use std::os::unix::io::{AsRawFd, BorrowedFd, FromRawFd, OwnedFd}; +use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd}; #[test] pub fn test_pselect() { let _mtx = crate::SIGNAL_MTX.lock(); let (r1, w1) = pipe().unwrap(); - write(w1, b"hi!").unwrap(); - let r1 = unsafe { OwnedFd::from_raw_fd(r1) }; + write(&w1, b"hi!").unwrap(); let (r2, _w2) = pipe().unwrap(); - let r2 = unsafe { OwnedFd::from_raw_fd(r2) }; let mut fd_set = FdSet::new(); - fd_set.insert(&r1); - fd_set.insert(&r2); + fd_set.insert(r1.as_fd()); + fd_set.insert(r2.as_fd()); let timeout = TimeSpec::seconds(10); let sigmask = SigSet::empty(); @@ -24,21 +22,19 @@ pub fn test_pselect() { 1, pselect(None, &mut fd_set, None, None, &timeout, &sigmask).unwrap() ); - assert!(fd_set.contains(&r1)); - assert!(!fd_set.contains(&r2)); + assert!(fd_set.contains(r1.as_fd())); + assert!(!fd_set.contains(r2.as_fd())); } #[test] pub fn test_pselect_nfds2() { let (r1, w1) = pipe().unwrap(); - write(w1, b"hi!").unwrap(); - let r1 = unsafe { OwnedFd::from_raw_fd(r1) }; + write(&w1, b"hi!").unwrap(); let (r2, _w2) = pipe().unwrap(); - let r2 = unsafe { OwnedFd::from_raw_fd(r2) }; let mut fd_set = FdSet::new(); - fd_set.insert(&r1); - fd_set.insert(&r2); + fd_set.insert(r1.as_fd()); + fd_set.insert(r2.as_fd()); let timeout = TimeSpec::seconds(10); assert_eq!( @@ -53,8 +49,8 @@ pub fn test_pselect_nfds2() { ) .unwrap() ); - assert!(fd_set.contains(&r1)); - assert!(!fd_set.contains(&r2)); + assert!(fd_set.contains(r1.as_fd())); + assert!(!fd_set.contains(r2.as_fd())); } macro_rules! generate_fdset_bad_fd_tests { @@ -64,7 +60,7 @@ macro_rules! generate_fdset_bad_fd_tests { #[should_panic] fn $method() { let bad_fd = unsafe{BorrowedFd::borrow_raw($fd)}; - FdSet::new().$method(&bad_fd); + FdSet::new().$method(bad_fd); } )* } @@ -72,7 +68,6 @@ macro_rules! generate_fdset_bad_fd_tests { mod test_fdset_too_large_fd { use super::*; - use std::convert::TryInto; generate_fdset_bad_fd_tests!( FD_SETSIZE.try_into().unwrap(), insert, @@ -80,3 +75,219 @@ mod test_fdset_too_large_fd { contains, ); } + +#[test] +fn fdset_insert() { + let mut fd_set = FdSet::new(); + + for i in 0..FD_SETSIZE { + let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) }; + assert!(!fd_set.contains(borrowed_i)); + } + + let fd_seven = unsafe { BorrowedFd::borrow_raw(7) }; + fd_set.insert(fd_seven); + + assert!(fd_set.contains(fd_seven)); +} + +#[test] +fn fdset_remove() { + let mut fd_set = FdSet::new(); + + for i in 0..FD_SETSIZE { + let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) }; + assert!(!fd_set.contains(borrowed_i)); + } + + let fd_seven = unsafe { BorrowedFd::borrow_raw(7) }; + fd_set.insert(fd_seven); + fd_set.remove(fd_seven); + + for i in 0..FD_SETSIZE { + let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) }; + assert!(!fd_set.contains(borrowed_i)); + } +} + +#[test] +#[allow(non_snake_case)] +fn fdset_clear() { + let mut fd_set = FdSet::new(); + let fd_one = unsafe { BorrowedFd::borrow_raw(1) }; + let fd_FD_SETSIZE_divided_by_two = + unsafe { BorrowedFd::borrow_raw((FD_SETSIZE / 2) as RawFd) }; + let fd_FD_SETSIZE_minus_one = + unsafe { BorrowedFd::borrow_raw((FD_SETSIZE - 1) as RawFd) }; + fd_set.insert(fd_one); + fd_set.insert(fd_FD_SETSIZE_divided_by_two); + fd_set.insert(fd_FD_SETSIZE_minus_one); + + fd_set.clear(); + + for i in 0..FD_SETSIZE { + let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) }; + assert!(!fd_set.contains(borrowed_i)); + } +} + +#[test] +fn fdset_highest() { + let mut set = FdSet::new(); + assert_eq!( + set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()), + None + ); + let fd_zero = unsafe { BorrowedFd::borrow_raw(0) }; + let fd_ninety = unsafe { BorrowedFd::borrow_raw(90) }; + set.insert(fd_zero); + assert_eq!( + set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()), + Some(0) + ); + set.insert(fd_ninety); + assert_eq!( + set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()), + Some(90) + ); + set.remove(fd_zero); + assert_eq!( + set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()), + Some(90) + ); + set.remove(fd_ninety); + assert_eq!( + set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()), + None + ); + + let fd_four = unsafe { BorrowedFd::borrow_raw(4) }; + let fd_five = unsafe { BorrowedFd::borrow_raw(5) }; + let fd_seven = unsafe { BorrowedFd::borrow_raw(7) }; + set.insert(fd_four); + set.insert(fd_five); + set.insert(fd_seven); + assert_eq!( + set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()), + Some(7) + ); +} + +#[test] +fn fdset_fds() { + let mut set = FdSet::new(); + let fd_zero = unsafe { BorrowedFd::borrow_raw(0) }; + let fd_ninety = unsafe { BorrowedFd::borrow_raw(90) }; + assert_eq!( + set.fds(None) + .map(|borrowed_fd| borrowed_fd.as_raw_fd()) + .collect::<Vec<_>>(), + vec![] + ); + set.insert(fd_zero); + assert_eq!( + set.fds(None) + .map(|borrowed_fd| borrowed_fd.as_raw_fd()) + .collect::<Vec<_>>(), + vec![0] + ); + set.insert(fd_ninety); + assert_eq!( + set.fds(None) + .map(|borrowed_fd| borrowed_fd.as_raw_fd()) + .collect::<Vec<_>>(), + vec![0, 90] + ); + + // highest limit + assert_eq!( + set.fds(Some(89)) + .map(|borrowed_fd| borrowed_fd.as_raw_fd()) + .collect::<Vec<_>>(), + vec![0] + ); + assert_eq!( + set.fds(Some(90)) + .map(|borrowed_fd| borrowed_fd.as_raw_fd()) + .collect::<Vec<_>>(), + vec![0, 90] + ); +} + +#[test] +fn test_select() { + let (r1, w1) = pipe().unwrap(); + let (r2, _w2) = pipe().unwrap(); + + write(&w1, b"hi!").unwrap(); + let mut fd_set = FdSet::new(); + fd_set.insert(r1.as_fd()); + fd_set.insert(r2.as_fd()); + + let mut timeout = TimeVal::seconds(10); + assert_eq!( + 1, + select(None, &mut fd_set, None, None, &mut timeout).unwrap() + ); + assert!(fd_set.contains(r1.as_fd())); + assert!(!fd_set.contains(r2.as_fd())); +} + +#[test] +fn test_select_nfds() { + let (r1, w1) = pipe().unwrap(); + let (r2, _w2) = pipe().unwrap(); + + write(&w1, b"hi!").unwrap(); + let mut fd_set = FdSet::new(); + fd_set.insert(r1.as_fd()); + fd_set.insert(r2.as_fd()); + + let mut timeout = TimeVal::seconds(10); + { + assert_eq!( + 1, + select( + Some( + fd_set + .highest() + .map(|borrowed_fd| borrowed_fd.as_raw_fd()) + .unwrap() + + 1 + ), + &mut fd_set, + None, + None, + &mut timeout + ) + .unwrap() + ); + } + assert!(fd_set.contains(r1.as_fd())); + assert!(!fd_set.contains(r2.as_fd())); +} + +#[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.as_fd()); + fd_set.insert(r2.as_fd()); + + let mut timeout = TimeVal::seconds(10); + assert_eq!( + 1, + select( + std::cmp::max(r1.as_raw_fd(), r2.as_raw_fd()) + 1, + &mut fd_set, + None, + None, + &mut timeout + ) + .unwrap() + ); + assert!(fd_set.contains(r1.as_fd())); + assert!(!fd_set.contains(r2.as_fd())); +} diff --git a/third_party/rust/nix/test/sys/test_signal.rs b/third_party/rust/nix/test/sys/test_signal.rs index ca25ff9ab0..bf607497be 100644 --- a/third_party/rust/nix/test/sys/test_signal.rs +++ b/third_party/rust/nix/test/sys/test_signal.rs @@ -1,9 +1,10 @@ -#[cfg(not(target_os = "redox"))] use nix::errno::Errno; use nix::sys::signal::*; use nix::unistd::*; -use std::convert::TryFrom; +use std::hash::{Hash, Hasher}; use std::sync::atomic::{AtomicBool, Ordering}; +#[cfg(not(target_os = "redox"))] +use std::thread; #[test] fn test_kill_none() { @@ -124,7 +125,7 @@ fn test_signal() { raise(Signal::SIGINT).unwrap(); assert!(SIGNALED.load(Ordering::Relaxed)); - #[cfg(not(any(target_os = "illumos", target_os = "solaris")))] + #[cfg(not(solarish))] assert_eq!( unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), handler @@ -132,7 +133,7 @@ fn test_signal() { // 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"))] + #[cfg(solarish)] assert_eq!( unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), SigHandler::SigDfl @@ -141,3 +142,314 @@ fn test_signal() { // Restore default signal handler unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(); } + +#[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(); +} + +#[cfg(any( + bsd, + linux_android, + solarish, + target_os = "haiku", + target_os = "hurd", + target_os = "aix", + target_os = "fushsia" +))] +#[test] +fn test_sigsuspend() { + // This test change signal handler + let _m = crate::SIGNAL_MTX.lock(); + static SIGNAL_RECIEVED: AtomicBool = AtomicBool::new(false); + extern "C" fn test_sigsuspend_handler(_: libc::c_int) { + assert!(!SIGNAL_RECIEVED.swap(true, Ordering::SeqCst)); + } + thread::spawn(|| { + const SIGNAL: Signal = Signal::SIGUSR1; + + // Add signal mask to this thread + let mut signal_set = SigSet::empty(); + signal_set.add(SIGNAL); + signal_set.thread_block().unwrap(); + + // Set signal handler and save old one. + let act = SigAction::new( + SigHandler::Handler(test_sigsuspend_handler), + SaFlags::empty(), + SigSet::empty(), + ); + let old_act = unsafe { sigaction(SIGNAL, &act) } + .expect("expect to be able to set new action and get old action"); + + raise(SIGNAL).expect("expect be able to send signal"); + // Now `SIGNAL` was sended but it is blocked. + let mut not_wait_set = SigSet::all(); + not_wait_set.remove(SIGNAL); + // signal handler must run in SigSet::suspend() + assert!(!SIGNAL_RECIEVED.load(Ordering::SeqCst)); + not_wait_set.suspend().unwrap(); + assert!(SIGNAL_RECIEVED.load(Ordering::SeqCst)); + + // Restore the signal handler. + unsafe { sigaction(SIGNAL, &old_act) } + .expect("expect to be able to restore old action "); + }) + .join() + .unwrap(); +} + +#[test] +fn test_from_sigset_t_unchecked() { + let src_set = SigSet::empty(); + let set = unsafe { SigSet::from_sigset_t_unchecked(*src_set.as_ref()) }; + + for signal in Signal::iterator() { + assert!(!set.contains(signal)); + } + + let src_set = SigSet::all(); + let set = unsafe { SigSet::from_sigset_t_unchecked(*src_set.as_ref()) }; + + for signal in Signal::iterator() { + assert!(set.contains(signal)); + } +} + +#[test] +fn test_eq_empty() { + let set0 = SigSet::empty(); + let set1 = SigSet::empty(); + assert_eq!(set0, set1); +} + +#[test] +fn test_eq_all() { + let set0 = SigSet::all(); + let set1 = SigSet::all(); + assert_eq!(set0, set1); +} + +#[test] +fn test_hash_empty() { + use std::collections::hash_map::DefaultHasher; + + let set0 = SigSet::empty(); + let mut h0 = DefaultHasher::new(); + set0.hash(&mut h0); + + let set1 = SigSet::empty(); + let mut h1 = DefaultHasher::new(); + set1.hash(&mut h1); + + assert_eq!(h0.finish(), h1.finish()); +} + +#[test] +fn test_hash_all() { + use std::collections::hash_map::DefaultHasher; + + let set0 = SigSet::all(); + let mut h0 = DefaultHasher::new(); + set0.hash(&mut h0); + + let set1 = SigSet::all(); + let mut h1 = DefaultHasher::new(); + set1.hash(&mut h1); + + assert_eq!(h0.finish(), h1.finish()); +} diff --git a/third_party/rust/nix/test/sys/test_signalfd.rs b/third_party/rust/nix/test/sys/test_signalfd.rs index 87153c9572..4e0971aba7 100644 --- a/third_party/rust/nix/test/sys/test_signalfd.rs +++ b/third_party/rust/nix/test/sys/test_signalfd.rs @@ -1,6 +1,40 @@ use std::convert::TryFrom; #[test] +fn create_signalfd() { + use nix::sys::{signal::SigSet, signalfd::SignalFd}; + + let mask = SigSet::empty(); + SignalFd::new(&mask).unwrap(); +} + +#[test] +fn create_signalfd_with_opts() { + use nix::sys::{ + signal::SigSet, + signalfd::{SfdFlags, SignalFd}, + }; + + let mask = SigSet::empty(); + SignalFd::with_flags(&mask, SfdFlags::SFD_CLOEXEC | SfdFlags::SFD_NONBLOCK) + .unwrap(); +} + +#[test] +fn read_empty_signalfd() { + use nix::sys::{ + signal::SigSet, + signalfd::{SfdFlags, 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()); +} + +#[test] fn test_signalfd() { use nix::sys::signal::{self, raise, SigSet, Signal}; use nix::sys::signalfd::SignalFd; @@ -25,3 +59,32 @@ fn test_signalfd() { let signo = Signal::try_from(res.ssi_signo as i32).unwrap(); assert_eq!(signo, signal::SIGUSR1); } + +/// Update the signal mask of an already existing signalfd. +#[test] +fn test_signalfd_setmask() { + 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(); + + let mut fd = SignalFd::new(&mask).unwrap(); + + mask.add(signal::SIGUSR1); + mask.thread_block().unwrap(); + fd.set_mask(&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/third_party/rust/nix/test/sys/test_socket.rs b/third_party/rust/nix/test/sys/test_socket.rs index ed1686e87d..90b8a6f528 100644 --- a/third_party/rust/nix/test/sys/test_socket.rs +++ b/third_party/rust/nix/test/sys/test_socket.rs @@ -1,4 +1,4 @@ -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] use crate::*; use libc::c_char; use nix::sys::socket::{getsockname, AddressFamily, UnixAddr}; @@ -21,7 +21,7 @@ pub fn test_timestamping() { }; use std::io::{IoSlice, IoSliceMut}; - let sock_addr = SockaddrIn::from_str("127.0.0.1:6790").unwrap(); + let sock_addr = SockaddrIn::from_str("127.0.0.1:6797").unwrap(); let ssock = socket( AddressFamily::Inet, @@ -72,15 +72,134 @@ pub fn test_timestamping() { assert!(std::time::Duration::from(diff).as_secs() < 60); } +#[cfg(target_os = "freebsd")] +#[test] +pub fn test_timestamping_realtime() { + use nix::sys::socket::{ + recvmsg, sendmsg, setsockopt, socket, sockopt::ReceiveTimestamp, + sockopt::TsClock, ControlMessageOwned, MsgFlags, SockFlag, SockType, + SockaddrIn, SocketTimestamp, + }; + use std::io::{IoSlice, IoSliceMut}; + + let sock_addr = SockaddrIn::from_str("127.0.0.1:6792").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.as_raw_fd(), &sock_addr).unwrap(); + + setsockopt(&rsock, ReceiveTimestamp, &true).unwrap(); + setsockopt(&rsock, TsClock, &SocketTimestamp::SO_TS_REALTIME).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::time::TimeVal); + sendmsg(ssock.as_raw_fd(), &iov1, &[], flags, Some(&sock_addr)).unwrap(); + let recv = + recvmsg::<()>(rsock.as_raw_fd(), &mut iov2, Some(&mut cmsg), flags) + .unwrap(); + + let mut ts = None; + for c in recv.cmsgs() { + if let ControlMessageOwned::ScmRealtime(timeval) = c { + ts = Some(timeval); + } + } + let ts = ts.expect("ScmRealtime 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); +} + +#[cfg(target_os = "freebsd")] +#[test] +pub fn test_timestamping_monotonic() { + use nix::sys::socket::{ + recvmsg, sendmsg, setsockopt, socket, sockopt::ReceiveTimestamp, + sockopt::TsClock, ControlMessageOwned, MsgFlags, SockFlag, SockType, + SockaddrIn, SocketTimestamp, + }; + use std::io::{IoSlice, IoSliceMut}; + + let sock_addr = SockaddrIn::from_str("127.0.0.1:6803").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.as_raw_fd(), &sock_addr).unwrap(); + + setsockopt(&rsock, ReceiveTimestamp, &true).unwrap(); + setsockopt(&rsock, TsClock, &SocketTimestamp::SO_TS_MONOTONIC).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::time::TimeVal); + sendmsg(ssock.as_raw_fd(), &iov1, &[], flags, Some(&sock_addr)).unwrap(); + let recv = + recvmsg::<()>(rsock.as_raw_fd(), &mut iov2, Some(&mut cmsg), flags) + .unwrap(); + + let mut ts = None; + for c in recv.cmsgs() { + if let ControlMessageOwned::ScmMonotonic(timeval) = c { + ts = Some(timeval); + } + } + let ts = ts.expect("ScmMonotonic is present"); + let sys_time = + ::nix::time::clock_gettime(::nix::time::ClockId::CLOCK_MONOTONIC) + .unwrap(); + let diff = sys_time - ts; // Monotonic clock sys_time must be greater + assert!(std::time::Duration::from(diff).as_secs() < 60); +} + #[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()) - }; + let expect: &[c_char] = + unsafe { slice::from_raw_parts(path.as_ptr().cast(), path.len()) }; assert_eq!(unsafe { &(*addr.as_ptr()).sun_path[..8] }, expect); assert_eq!(addr.path(), Some(actual)); @@ -105,7 +224,7 @@ pub fn test_addr_equality_path() { assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2)); } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[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"); @@ -113,7 +232,7 @@ pub fn test_abstract_sun_path_too_long() { addr.expect_err("assertion failed"); } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[test] pub fn test_addr_equality_abstract() { let name = String::from("nix\0abstract\0test"); @@ -129,7 +248,7 @@ pub fn test_addr_equality_abstract() { } // Test getting/setting abstract addresses (without unix socket creation) -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[test] pub fn test_abstract_uds_addr() { let empty = String::new(); @@ -151,7 +270,7 @@ pub fn test_abstract_uds_addr() { } // Test getting an unnamed address (without unix socket creation) -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[test] pub fn test_unnamed_uds_addr() { use crate::nix::sys::socket::SockaddrLike; @@ -200,7 +319,7 @@ pub fn test_socketpair() { SockFlag::empty(), ) .unwrap(); - write(fd1.as_raw_fd(), b"hello").unwrap(); + write(&fd1, b"hello").unwrap(); let mut buf = [0; 5]; read(fd2.as_raw_fd(), &mut buf).unwrap(); @@ -315,7 +434,7 @@ mod recvfrom { #[test] pub fn udp() { - let std_sa = SocketAddrV4::from_str("127.0.0.1:6789").unwrap(); + let std_sa = SocketAddrV4::from_str("127.0.0.1:6795").unwrap(); let sock_addr = SockaddrIn::from(std_sa); let rsock = socket( AddressFamily::Inet, @@ -437,12 +556,7 @@ mod recvfrom { } } - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", - ))] + #[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))] #[test] pub fn udp_sendmmsg() { use std::io::IoSlice; @@ -504,12 +618,7 @@ mod recvfrom { assert_eq!(AddressFamily::Inet, from.unwrap().family().unwrap()); } - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", - ))] + #[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))] #[test] pub fn udp_recvmmsg() { use nix::sys::socket::{recvmmsg, MsgFlags}; @@ -565,7 +674,7 @@ mod recvfrom { let res: Vec<RecvMsg<SockaddrIn>> = recvmmsg( rsock.as_raw_fd(), &mut data, - msgs.iter(), + msgs.iter_mut(), MsgFlags::empty(), None, ) @@ -585,12 +694,7 @@ mod recvfrom { send_thread.join().unwrap(); } - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", - ))] + #[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))] #[test] pub fn udp_recvmmsg_dontwait_short_read() { use nix::sys::socket::{recvmmsg, MsgFlags}; @@ -653,7 +757,7 @@ mod recvfrom { let res: Vec<RecvMsg<SockaddrIn>> = recvmmsg( rsock.as_raw_fd(), &mut data, - msgs.iter(), + msgs.iter_mut(), MsgFlags::MSG_DONTWAIT, None, ) @@ -674,10 +778,10 @@ mod recvfrom { #[test] pub fn udp_inet6() { let addr = std::net::Ipv6Addr::from_str("::1").unwrap(); - let rport = 6789; + let rport = 6796; let rstd_sa = SocketAddrV6::new(addr, rport, 0, 0); let raddr = SockaddrIn6::from(rstd_sa); - let sport = 6790; + let sport = 6798; let sstd_sa = SocketAddrV6::new(addr, sport, 0, 0); let saddr = SockaddrIn6::from(sstd_sa); let rsock = socket( @@ -757,7 +861,7 @@ pub fn test_scm_rights() { { let iov = [IoSlice::new(b"hello")]; - let fds = [r]; + let fds = [r.as_raw_fd()]; let cmsg = ControlMessage::ScmRights(&fds); assert_eq!( sendmsg::<()>( @@ -770,7 +874,6 @@ pub fn test_scm_rights() { .unwrap(), 5 ); - close(r).unwrap(); } { @@ -803,16 +906,15 @@ pub fn test_scm_rights() { let received_r = received_r.expect("Did not receive passed fd"); // Ensure that the received file descriptor works - write(w.as_raw_fd(), b"world").unwrap(); + write(&w, b"world").unwrap(); let mut buf = [0u8; 5]; read(received_r.as_raw_fd(), &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(linux_android)] #[cfg_attr(qemu, ignore)] #[test] pub fn test_af_alg_cipher() { @@ -905,7 +1007,7 @@ pub fn test_af_alg_cipher() { // 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(linux_android)] #[cfg_attr(qemu, ignore)] #[test] pub fn test_af_alg_aead() { @@ -1039,7 +1141,7 @@ pub fn test_af_alg_aead() { // 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"))] +#[cfg(any(target_os = "linux", apple_targets, target_os = "netbsd"))] #[test] pub fn test_sendmsg_ipv4packetinfo() { use cfg_if::cfg_if; @@ -1101,7 +1203,7 @@ pub fn test_sendmsg_ipv4packetinfo() { // test from). #[cfg(any( target_os = "linux", - target_os = "macos", + apple_targets, target_os = "netbsd", target_os = "freebsd" ))] @@ -1158,12 +1260,7 @@ pub fn test_sendmsg_ipv6packetinfo() { // // 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", -))] +#[cfg(any(freebsdlike, netbsdlike))] #[test] pub fn test_sendmsg_ipv4sendsrcaddr() { use nix::sys::socket::{ @@ -1302,7 +1399,7 @@ pub fn test_sendmsg_empty_cmsgs() { ) .unwrap(); - for _ in msg.cmsgs() { + if msg.cmsgs().next().is_some() { panic!("unexpected cmsg"); } assert!(!msg @@ -1312,19 +1409,14 @@ pub fn test_sendmsg_empty_cmsgs() { } } -#[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "freebsd", - target_os = "dragonfly", -))] +#[cfg(any(linux_android, freebsdlike))] #[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"))] + #[cfg(linux_android)] use nix::sys::socket::{setsockopt, sockopt::PassCred}; use nix::unistd::{getgid, getpid, getuid}; use std::io::{IoSlice, IoSliceMut}; @@ -1336,16 +1428,16 @@ fn test_scm_credentials() { SockFlag::empty(), ) .unwrap(); - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] setsockopt(&recv, PassCred, &true).unwrap(); { let iov = [IoSlice::new(b"hello")]; - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] let cred = UnixCredentials::new(); - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] let cmsg = ControlMessage::ScmCredentials(&cred); - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg(freebsdlike)] let cmsg = ControlMessage::ScmCreds; assert_eq!( sendmsg::<()>( @@ -1376,9 +1468,9 @@ fn test_scm_credentials() { for cmsg in msg.cmsgs() { let cred = match cmsg { - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] ControlMessageOwned::ScmCredentials(cred) => cred, - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg(freebsdlike)] ControlMessageOwned::ScmCreds(cred) => cred, other => panic!("unexpected cmsg {other:?}"), }; @@ -1398,7 +1490,7 @@ fn test_scm_credentials() { /// Ensure that we can send `SCM_CREDENTIALS` and `SCM_RIGHTS` with a single /// `sendmsg` call. -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] // qemu's handling of multiple cmsgs is bugged, ignore tests under emulation // see https://bugs.launchpad.net/qemu/+bug/1781280 #[cfg_attr(qemu, ignore)] @@ -1410,7 +1502,7 @@ fn test_scm_credentials_and_rights() { /// Ensure that passing a an oversized control message buffer to recvmsg /// still works. -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] // qemu's handling of multiple cmsgs is bugged, ignore tests under emulation // see https://bugs.launchpad.net/qemu/+bug/1781280 #[cfg_attr(qemu, ignore)] @@ -1420,7 +1512,7 @@ fn test_too_large_cmsgspace() { test_impl_scm_credentials_and_rights(space); } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) { use libc::ucred; use nix::sys::socket::sockopt::PassCred; @@ -1451,7 +1543,7 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) { gid: getgid().as_raw(), } .into(); - let fds = [r]; + let fds = [r.as_raw_fd()]; let cmsgs = [ ControlMessage::ScmCredentials(&cred), ControlMessage::ScmRights(&fds), @@ -1467,7 +1559,6 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) { .unwrap(), 5 ); - close(r).unwrap(); } { @@ -1510,18 +1601,19 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) { let received_r = received_r.expect("Did not receive passed fd"); // Ensure that the received file descriptor works - write(w.as_raw_fd(), b"world").unwrap(); + write(&w, b"world").unwrap(); let mut buf = [0u8; 5]; read(received_r.as_raw_fd(), &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::{ + accept, bind, connect, listen, socket, Backlog, UnixAddr, + }; use nix::sys::socket::{SockFlag, SockType}; use nix::unistd::{read, write}; use std::thread; @@ -1537,7 +1629,7 @@ pub fn test_named_unixdomain() { .expect("socket failed"); let sockaddr = UnixAddr::new(&sockname).unwrap(); bind(s1.as_raw_fd(), &sockaddr).expect("bind failed"); - listen(&s1, 10).expect("listen failed"); + listen(&s1, Backlog::new(10).unwrap()).expect("listen failed"); let thr = thread::spawn(move || { let s2 = socket( @@ -1548,7 +1640,7 @@ pub fn test_named_unixdomain() { ) .expect("socket failed"); connect(s2.as_raw_fd(), &sockaddr).expect("connect failed"); - write(s2.as_raw_fd(), b"hello").expect("write failed"); + write(&s2, b"hello").expect("write failed"); }); let s3 = accept(s1.as_raw_fd()).expect("accept failed"); @@ -1560,8 +1652,16 @@ pub fn test_named_unixdomain() { assert_eq!(&buf[..], b"hello"); } +#[test] +pub fn test_listen_wrongbacklog() { + use nix::sys::socket::Backlog; + + assert!(Backlog::new(libc::SOMAXCONN + 1).is_err()); + assert!(Backlog::new(-2).is_err()); +} + // Test using unnamed unix domain addresses -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[test] pub fn test_unnamed_unixdomain() { use nix::sys::socket::{getsockname, socketpair}; @@ -1581,7 +1681,7 @@ pub fn test_unnamed_unixdomain() { } // Test creating and using unnamed unix domain addresses for autobinding sockets -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[test] pub fn test_unnamed_unixdomain_autobind() { use nix::sys::socket::{bind, getsockname, socket}; @@ -1609,7 +1709,7 @@ pub fn test_unnamed_unixdomain_autobind() { } // Test creating and using named system control sockets -#[cfg(any(target_os = "macos", target_os = "ios"))] +#[cfg(apple_targets)] #[test] pub fn test_syscontrol() { use nix::errno::Errno; @@ -1635,15 +1735,7 @@ pub fn test_syscontrol() { // connect(fd.as_raw_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", -))] +#[cfg(any(bsd, linux_android))] fn loopback_address( family: AddressFamily, ) -> Option<nix::ifaddrs::InterfaceAddress> { @@ -1670,20 +1762,16 @@ fn loopback_address( }) } -#[cfg(any( - target_os = "android", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", -))] +#[cfg(any(linux_android, apple_targets, 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 = "mips32r6", target_arch = "mips64", + target_arch = "mips64r6", target_arch = "powerpc64", ) ), @@ -1765,20 +1853,16 @@ pub fn test_recv_ipv4pktinfo() { } } -#[cfg(any( - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", -))] +#[cfg(bsd)] // qemu doesn't seem to be emulating this correctly in these architectures #[cfg_attr( all( qemu, any( target_arch = "mips", + target_arch = "mips32r6", target_arch = "mips64", + target_arch = "mips64r6", target_arch = "powerpc64", ) ), @@ -1883,7 +1967,7 @@ pub fn test_recvif() { } } -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +#[cfg(any(linux_android, target_os = "freebsd"))] #[cfg_attr(qemu, ignore)] #[test] pub fn test_recvif_ipv4() { @@ -1969,7 +2053,7 @@ pub fn test_recvif_ipv4() { } } -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +#[cfg(any(linux_android, target_os = "freebsd"))] #[cfg_attr(qemu, ignore)] #[test] pub fn test_recvif_ipv6() { @@ -2055,22 +2139,16 @@ pub fn test_recvif_ipv6() { } } -#[cfg(any( - target_os = "android", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", -))] +#[cfg(any(linux_android, target_os = "freebsd", apple_targets, netbsdlike))] // qemu doesn't seem to be emulating this correctly in these architectures #[cfg_attr( all( qemu, any( target_arch = "mips", + target_arch = "mips32r6", target_arch = "mips64", + target_arch = "mips64r6", target_arch = "powerpc64", ) ), @@ -2152,7 +2230,7 @@ pub fn test_recv_ipv6pktinfo() { } } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[test] pub fn test_vsock() { use nix::sys::socket::SockaddrLike; @@ -2192,7 +2270,7 @@ pub fn test_vsock() { assert_eq!(addr3.as_ref().svm_port, addr1.port()); } -#[cfg(target_os = "macos")] +#[cfg(apple_targets)] #[test] pub fn test_vsock() { use nix::sys::socket::SockaddrLike; @@ -2329,12 +2407,17 @@ fn test_recvmmsg_timestampns() { // 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 iov = vec![[IoSliceMut::new(&mut buffer)]]; let mut data = MultiHeaders::preallocate(1, Some(cmsgspace)); - let r: Vec<RecvMsg<()>> = - recvmmsg(in_socket.as_raw_fd(), &mut data, iov.iter(), flags, None) - .unwrap() - .collect(); + let r: Vec<RecvMsg<()>> = recvmmsg( + in_socket.as_raw_fd(), + &mut data, + iov.iter_mut(), + flags, + None, + ) + .unwrap() + .collect(); let rtime = match r[0].cmsgs().next() { Some(ControlMessageOwned::ScmTimestampns(rtime)) => rtime, Some(_) => panic!("Unexpected control message"), @@ -2353,7 +2436,7 @@ fn test_recvmmsg_timestampns() { // 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"))] +#[cfg(any(linux_android, target_os = "fuchsia"))] #[test] fn test_recvmsg_rxq_ovfl() { use nix::sys::socket::sockopt::{RcvBuf, RxqOvfl}; @@ -2447,7 +2530,7 @@ fn test_recvmsg_rxq_ovfl() { assert_eq!(drop_counter, 1); } -#[cfg(any(target_os = "linux", target_os = "android",))] +#[cfg(linux_android)] mod linux_errqueue { use super::FromStr; use nix::sys::socket::*; @@ -2685,3 +2768,160 @@ pub fn test_txtime() { recvmsg::<()>(rsock.as_raw_fd(), &mut iov2, None, MsgFlags::empty()) .unwrap(); } + +// cfg needed for capability check. +#[cfg(linux_android)] +#[test] +fn test_icmp_protocol() { + use nix::sys::socket::{ + sendto, socket, AddressFamily, MsgFlags, SockFlag, SockProtocol, + SockType, SockaddrIn, + }; + + require_capability!("test_icmp_protocol", CAP_NET_RAW); + + let owned_fd = socket( + AddressFamily::Inet, + SockType::Raw, + SockFlag::empty(), + SockProtocol::Icmp, + ) + .unwrap(); + + // Send a minimal ICMP packet with no payload. + let packet = [ + 0x08, // Type + 0x00, // Code + 0x84, 0x85, // Checksum + 0x73, 0x8a, // ID + 0x00, 0x00, // Sequence Number + ]; + + let dest_addr = SockaddrIn::new(127, 0, 0, 1, 0); + sendto(owned_fd.as_raw_fd(), &packet, &dest_addr, MsgFlags::empty()) + .unwrap(); +} + +// test contains both recvmmsg and timestaping which is linux only +// there are existing tests for recvmmsg only in tests/ +#[cfg_attr(qemu, ignore)] +#[cfg(target_os = "linux")] +#[test] +fn test_recvmm2() -> nix::Result<()> { + use nix::sys::{ + socket::{ + bind, recvmmsg, sendmsg, setsockopt, socket, sockopt::Timestamping, + AddressFamily, ControlMessageOwned, MsgFlags, MultiHeaders, + SockFlag, SockType, SockaddrIn, TimestampingFlag, Timestamps, + }, + time::TimeSpec, + }; + use std::io::{IoSlice, IoSliceMut}; + use std::os::unix::io::AsRawFd; + use std::str::FromStr; + + 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, + )?; + + bind(rsock.as_raw_fd(), &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!(Timestamps); + sendmsg(ssock.as_raw_fd(), &iov1, &[], flags, Some(&sock_addr)).unwrap(); + + let mut data = MultiHeaders::<()>::preallocate(recv_iovs.len(), Some(cmsg)); + + let t = TimeSpec::from_duration(std::time::Duration::from_secs(10)); + + let recv = recvmmsg( + rsock.as_raw_fd(), + &mut data, + recv_iovs.iter_mut(), + 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 = nix::time::clock_gettime( + nix::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(()) +} + +#[cfg(not(target_os = "redox"))] +#[test] +fn can_use_cmsg_space() { + let _ = cmsg_space!(u8); +} + +#[cfg(not(any(linux_android, target_os = "redox", target_os = "haiku")))] +#[test] +fn can_open_routing_socket() { + use nix::sys::socket::{socket, AddressFamily, SockFlag, SockType}; + + let _ = + socket(AddressFamily::Route, SockType::Raw, SockFlag::empty(), None) + .expect("Failed to open routing socket"); +} diff --git a/third_party/rust/nix/test/sys/test_sockopt.rs b/third_party/rust/nix/test/sys/test_sockopt.rs index 0e34917325..a99d4e39ed 100644 --- a/third_party/rust/nix/test/sys/test_sockopt.rs +++ b/third_party/rust/nix/test/sys/test_sockopt.rs @@ -1,14 +1,14 @@ -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] use crate::*; use nix::sys::socket::{ getsockopt, setsockopt, socket, sockopt, AddressFamily, SockFlag, SockProtocol, SockType, }; use rand::{thread_rng, Rng}; -use std::os::unix::io::AsRawFd; +use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd}; // NB: FreeBSD supports LOCAL_PEERCRED for SOCK_SEQPACKET, but OSX does not. -#[cfg(any(target_os = "dragonfly", target_os = "freebsd",))] +#[cfg(freebsdlike)] #[test] pub fn test_local_peercred_seqpacket() { use nix::{ @@ -29,12 +29,7 @@ pub fn test_local_peercred_seqpacket() { assert_eq!(Gid::from_raw(xucred.groups()[0]), Gid::current()); } -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "ios" -))] +#[cfg(any(freebsdlike, apple_targets))] #[test] pub fn test_local_peercred_stream() { use nix::{ @@ -55,7 +50,7 @@ pub fn test_local_peercred_stream() { assert_eq!(Gid::from_raw(xucred.groups()[0]), Gid::current()); } -#[cfg(any(target_os = "ios", target_os = "macos"))] +#[cfg(apple_targets)] #[test] pub fn test_local_peer_pid() { use nix::sys::socket::socketpair; @@ -108,15 +103,42 @@ fn test_so_buf() { assert!(actual >= bufsize); } +#[cfg(target_os = "freebsd")] +#[test] +fn test_so_listen_q_limit() { + use nix::sys::socket::{bind, listen, Backlog, SockaddrIn}; + use std::net::SocketAddrV4; + use std::str::FromStr; + + let std_sa = SocketAddrV4::from_str("127.0.0.1:4004").unwrap(); + let sock_addr = SockaddrIn::from(std_sa); + + let rsock = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + SockProtocol::Tcp, + ) + .unwrap(); + bind(rsock.as_raw_fd(), &sock_addr).unwrap(); + let pre_limit = getsockopt(&rsock, sockopt::ListenQLimit).unwrap(); + assert_eq!(pre_limit, 0); + listen(&rsock, Backlog::new(42).unwrap()).unwrap(); + let post_limit = getsockopt(&rsock, sockopt::ListenQLimit).unwrap(); + assert_eq!(post_limit, 42); +} + #[test] fn test_so_tcp_maxseg() { - use nix::sys::socket::{accept, bind, connect, listen, SockaddrIn}; + use nix::sys::socket::{ + accept, bind, connect, getsockname, listen, Backlog, SockaddrIn, + }; use nix::unistd::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 std_sa = SocketAddrV4::from_str("127.0.0.1:0").unwrap(); + let mut sock_addr = SockaddrIn::from(std_sa); let rsock = socket( AddressFamily::Inet, @@ -126,13 +148,14 @@ fn test_so_tcp_maxseg() { ) .unwrap(); bind(rsock.as_raw_fd(), &sock_addr).unwrap(); - listen(&rsock, 10).unwrap(); + sock_addr = getsockname(rsock.as_raw_fd()).unwrap(); + listen(&rsock, Backlog::new(10).unwrap()).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"))] { + if #[cfg(linux_android)] { let segsize: u32 = 873; assert!(initial < segsize); setsockopt(&rsock, sockopt::TcpMaxSeg, &segsize).unwrap(); @@ -151,12 +174,13 @@ fn test_so_tcp_maxseg() { .unwrap(); connect(ssock.as_raw_fd(), &sock_addr).unwrap(); let rsess = accept(rsock.as_raw_fd()).unwrap(); - write(rsess, b"hello").unwrap(); + let rsess = unsafe { OwnedFd::from_raw_fd(rsess) }; + 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"))] { + if #[cfg(linux_android)] { assert!((segsize - 100) <= actual); assert!(actual <= segsize); } else { @@ -181,11 +205,10 @@ fn test_so_type() { /// 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",))] +#[cfg(linux_android)] #[test] fn test_so_type_unknown() { use nix::errno::Errno; - use std::os::unix::io::{FromRawFd, OwnedFd}; require_capability!("test_so_type", CAP_NET_RAW); let raw_fd = unsafe { libc::socket(libc::AF_PACKET, libc::SOCK_PACKET, 0) }; @@ -229,7 +252,7 @@ fn test_tcp_congestion() { } #[test] -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] fn test_bindtodevice() { skip_if_not_root!("test_bindtodevice"); @@ -259,12 +282,7 @@ fn test_so_tcp_keepalive() { 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" - ))] + #[cfg(any(linux_android, freebsdlike))] { let x = getsockopt(&fd, sockopt::TcpKeepIdle).unwrap(); setsockopt(&fd, sockopt::TcpKeepIdle, &(x + 1)).unwrap(); @@ -281,14 +299,14 @@ fn test_so_tcp_keepalive() { } #[test] -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[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_sa = SocketAddrV4::from_str("127.0.0.1:0").unwrap(); let std_sb = SocketAddrV4::from_str("127.0.0.1:4002").unwrap(); let usock = socket( @@ -308,7 +326,7 @@ fn test_get_mtu() { } #[test] -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +#[cfg(any(linux_android, target_os = "freebsd"))] fn test_ttl_opts() { let fd4 = socket( AddressFamily::Inet, @@ -331,7 +349,48 @@ fn test_ttl_opts() { } #[test] -#[cfg(any(target_os = "ios", target_os = "macos"))] +#[cfg(any(linux_android, target_os = "freebsd"))] +fn test_multicast_ttl_opts_ipv4() { + let fd4 = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + setsockopt(&fd4, sockopt::IpMulticastTtl, &2) + .expect("setting ipmulticastttl on an inet socket should succeed"); +} + +#[test] +#[cfg(linux_android)] +fn test_multicast_ttl_opts_ipv6() { + let fd6 = socket( + AddressFamily::Inet6, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + setsockopt(&fd6, sockopt::IpMulticastTtl, &2) + .expect("setting ipmulticastttl on an inet6 socket should succeed"); +} + +#[test] +fn test_ipv6_multicast_hops() { + let fd6 = socket( + AddressFamily::Inet6, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + setsockopt(&fd6, sockopt::Ipv6MulticastHops, &7) + .expect("setting ipv6multicasthops on an inet6 socket should succeed"); +} + +#[test] +#[cfg(apple_targets)] fn test_dontfrag_opts() { let fd4 = socket( AddressFamily::Inet, @@ -361,12 +420,7 @@ fn test_dontfrag_opts() { } #[test] -#[cfg(any( - target_os = "android", - target_os = "ios", - target_os = "linux", - target_os = "macos", -))] +#[cfg(any(linux_android, apple_targets))] // Disable the test under emulation because it fails in Cirrus-CI. Lack // of QEMU support is suspected. #[cfg_attr(qemu, ignore)] @@ -446,3 +500,331 @@ fn test_ipv6_tclass() { setsockopt(&fd, sockopt::Ipv6TClass, &class).unwrap(); assert_eq!(getsockopt(&fd, sockopt::Ipv6TClass).unwrap(), class); } + +#[test] +#[cfg(target_os = "freebsd")] +fn test_receive_timestamp() { + let fd = socket( + AddressFamily::Inet6, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + setsockopt(&fd, sockopt::ReceiveTimestamp, &true).unwrap(); + assert!(getsockopt(&fd, sockopt::ReceiveTimestamp).unwrap()); +} + +#[test] +#[cfg(target_os = "freebsd")] +fn test_ts_clock_realtime_micro() { + use nix::sys::socket::SocketTimestamp; + + let fd = socket( + AddressFamily::Inet6, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + + // FreeBSD setsockopt docs say to set SO_TS_CLOCK after setting SO_TIMESTAMP. + setsockopt(&fd, sockopt::ReceiveTimestamp, &true).unwrap(); + + setsockopt( + &fd, + sockopt::TsClock, + &SocketTimestamp::SO_TS_REALTIME_MICRO, + ) + .unwrap(); + assert_eq!( + getsockopt(&fd, sockopt::TsClock).unwrap(), + SocketTimestamp::SO_TS_REALTIME_MICRO + ); +} + +#[test] +#[cfg(target_os = "freebsd")] +fn test_ts_clock_bintime() { + use nix::sys::socket::SocketTimestamp; + + let fd = socket( + AddressFamily::Inet6, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + + // FreeBSD setsockopt docs say to set SO_TS_CLOCK after setting SO_TIMESTAMP. + setsockopt(&fd, sockopt::ReceiveTimestamp, &true).unwrap(); + + setsockopt(&fd, sockopt::TsClock, &SocketTimestamp::SO_TS_BINTIME).unwrap(); + assert_eq!( + getsockopt(&fd, sockopt::TsClock).unwrap(), + SocketTimestamp::SO_TS_BINTIME + ); +} + +#[test] +#[cfg(target_os = "freebsd")] +fn test_ts_clock_realtime() { + use nix::sys::socket::SocketTimestamp; + + let fd = socket( + AddressFamily::Inet6, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + + // FreeBSD setsockopt docs say to set SO_TS_CLOCK after setting SO_TIMESTAMP. + setsockopt(&fd, sockopt::ReceiveTimestamp, &true).unwrap(); + + setsockopt(&fd, sockopt::TsClock, &SocketTimestamp::SO_TS_REALTIME) + .unwrap(); + assert_eq!( + getsockopt(&fd, sockopt::TsClock).unwrap(), + SocketTimestamp::SO_TS_REALTIME + ); +} + +#[test] +#[cfg(target_os = "freebsd")] +fn test_ts_clock_monotonic() { + use nix::sys::socket::SocketTimestamp; + + let fd = socket( + AddressFamily::Inet6, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + + // FreeBSD setsockopt docs say to set SO_TS_CLOCK after setting SO_TIMESTAMP. + setsockopt(&fd, sockopt::ReceiveTimestamp, &true).unwrap(); + + setsockopt(&fd, sockopt::TsClock, &SocketTimestamp::SO_TS_MONOTONIC) + .unwrap(); + assert_eq!( + getsockopt(&fd, sockopt::TsClock).unwrap(), + SocketTimestamp::SO_TS_MONOTONIC + ); +} + +#[test] +#[cfg(linux_android)] +// Disable the test under emulation because it fails with ENOPROTOOPT in CI +// on cross target. Lack of QEMU support is suspected. +#[cfg_attr(qemu, ignore)] +fn test_ip_bind_address_no_port() { + let fd = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + SockProtocol::Tcp, + ) + .unwrap(); + setsockopt(&fd, sockopt::IpBindAddressNoPort, &true).expect( + "setting IP_BIND_ADDRESS_NO_PORT on an inet stream socket should succeed", + ); + assert!(getsockopt(&fd, sockopt::IpBindAddressNoPort).expect( + "getting IP_BIND_ADDRESS_NO_PORT on an inet stream socket should succeed", + )); + setsockopt(&fd, sockopt::IpBindAddressNoPort, &false).expect( + "unsetting IP_BIND_ADDRESS_NO_PORT on an inet stream socket should succeed", + ); + assert!(!getsockopt(&fd, sockopt::IpBindAddressNoPort).expect( + "getting IP_BIND_ADDRESS_NO_PORT on an inet stream socket should succeed", + )); +} + +#[test] +#[cfg(linux_android)] +fn test_tcp_fast_open_connect() { + let fd = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + SockProtocol::Tcp, + ) + .unwrap(); + setsockopt(&fd, sockopt::TcpFastOpenConnect, &true).expect( + "setting TCP_FASTOPEN_CONNECT on an inet stream socket should succeed", + ); + assert!(getsockopt(&fd, sockopt::TcpFastOpenConnect).expect( + "getting TCP_FASTOPEN_CONNECT on an inet stream socket should succeed", + )); + setsockopt(&fd, sockopt::TcpFastOpenConnect, &false).expect( + "unsetting TCP_FASTOPEN_CONNECT on an inet stream socket should succeed", + ); + assert!(!getsockopt(&fd, sockopt::TcpFastOpenConnect).expect( + "getting TCP_FASTOPEN_CONNECT on an inet stream socket should succeed", + )); +} + +#[cfg(linux_android)] +#[test] +fn can_get_peercred_on_unix_socket() { + use nix::sys::socket::{socketpair, sockopt, SockFlag, SockType}; + + let (a, b) = socketpair( + AddressFamily::Unix, + SockType::Stream, + None, + SockFlag::empty(), + ) + .unwrap(); + let a_cred = getsockopt(&a, sockopt::PeerCredentials).unwrap(); + let b_cred = getsockopt(&b, sockopt::PeerCredentials).unwrap(); + assert_eq!(a_cred, b_cred); + assert_ne!(a_cred.pid(), 0); +} + +#[test] +fn is_socket_type_unix() { + use nix::sys::socket::{socketpair, sockopt, SockFlag, SockType}; + + let (a, _b) = socketpair( + AddressFamily::Unix, + SockType::Stream, + None, + SockFlag::empty(), + ) + .unwrap(); + let a_type = getsockopt(&a, sockopt::SockType).unwrap(); + assert_eq!(a_type, SockType::Stream); +} + +#[test] +fn is_socket_type_dgram() { + use nix::sys::socket::{ + getsockopt, sockopt, AddressFamily, SockFlag, SockType, + }; + + let s = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + let s_type = getsockopt(&s, sockopt::SockType).unwrap(); + assert_eq!(s_type, SockType::Datagram); +} + +#[cfg(any(target_os = "freebsd", target_os = "linux"))] +#[test] +fn can_get_listen_on_tcp_socket() { + use nix::sys::socket::{ + getsockopt, listen, socket, sockopt, AddressFamily, Backlog, SockFlag, + SockType, + }; + + let s = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + None, + ) + .unwrap(); + let s_listening = getsockopt(&s, sockopt::AcceptConn).unwrap(); + assert!(!s_listening); + listen(&s, Backlog::new(10).unwrap()).unwrap(); + let s_listening2 = getsockopt(&s, sockopt::AcceptConn).unwrap(); + assert!(s_listening2); +} + +#[cfg(target_os = "linux")] +// Some architectures running under cross don't support `setsockopt(SOL_TCP, TCP_ULP)` +// because the cross image is based on Ubuntu 16.04 which predates TCP ULP support +// (it was added in kernel v4.13 released in 2017). For these architectures, +// the `setsockopt(SOL_TCP, TCP_ULP, "tls", sizeof("tls"))` call succeeds +// but the subsequent `setsockopt(SOL_TLS, TLS_TX, ...)` call fails with `ENOPROTOOPT`. +// It's as if the first `setsockopt` call enabled some other option, not `TCP_ULP`. +// For example, `strace` says: +// +// [pid 813] setsockopt(4, SOL_TCP, 0x1f /* TCP_??? */, [7564404], 4) = 0 +// +// It's not clear why `setsockopt(SOL_TCP, TCP_ULP)` succeeds if the container image libc doesn't support it, +// but in any case we can't run the test on such an architecture, so skip it. +#[cfg_attr(qemu, ignore)] +#[test] +fn test_ktls() { + use nix::sys::socket::{ + accept, bind, connect, getsockname, listen, Backlog, SockaddrIn, + }; + use std::net::SocketAddrV4; + use std::str::FromStr; + + let std_sa = SocketAddrV4::from_str("127.0.0.1:0").unwrap(); + let mut sock_addr = SockaddrIn::from(std_sa); + + let rsock = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + SockProtocol::Tcp, + ) + .unwrap(); + bind(rsock.as_raw_fd(), &sock_addr).unwrap(); + sock_addr = getsockname(rsock.as_raw_fd()).unwrap(); + listen(&rsock, Backlog::new(10).unwrap()).unwrap(); + + let ssock = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + SockProtocol::Tcp, + ) + .unwrap(); + connect(ssock.as_raw_fd(), &sock_addr).unwrap(); + + let _rsess = accept(rsock.as_raw_fd()).unwrap(); + + match setsockopt(&ssock, sockopt::TcpUlp::default(), b"tls") { + Ok(()) => (), + + // TLS ULP is not enabled, so we can't test kTLS. + Err(nix::Error::ENOENT) => skip!("TLS ULP is not enabled"), + + Err(err) => panic!("{err:?}"), + } + + // In real life we would do a TLS handshake and extract the protocol version and secrets. + // For this test we just make some up. + + let tx = sockopt::TlsCryptoInfo::Aes128Gcm(libc::tls12_crypto_info_aes_gcm_128 { + info: libc::tls_crypto_info { + version: libc::TLS_1_2_VERSION, + cipher_type: libc::TLS_CIPHER_AES_GCM_128, + }, + iv: *b"\x04\x05\x06\x07\x08\x09\x0a\x0b", + key: *b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + salt: *b"\x00\x01\x02\x03", + rec_seq: *b"\x00\x00\x00\x00\x00\x00\x00\x00", + }); + setsockopt(&ssock, sockopt::TcpTlsTx, &tx) + .expect("setting TLS_TX after enabling TLS ULP should succeed"); + + let rx = sockopt::TlsCryptoInfo::Aes128Gcm(libc::tls12_crypto_info_aes_gcm_128 { + info: libc::tls_crypto_info { + version: libc::TLS_1_2_VERSION, + cipher_type: libc::TLS_CIPHER_AES_GCM_128, + }, + iv: *b"\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb", + key: *b"\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef", + salt: *b"\xf0\xf1\xf2\xf3", + rec_seq: *b"\x00\x00\x00\x00\x00\x00\x00\x00", + }); + match setsockopt(&ssock, sockopt::TcpTlsRx, &rx) { + Ok(()) => (), + Err(nix::Error::ENOPROTOOPT) => { + // TLS_TX was added in v4.13 and TLS_RX in v4.17, so we appear to be between that range. + // It's good enough that TLS_TX worked, so let the test succeed. + } + Err(err) => panic!("{err:?}"), + } +} diff --git a/third_party/rust/nix/test/sys/test_statfs.rs b/third_party/rust/nix/test/sys/test_statfs.rs new file mode 100644 index 0000000000..66b3f2ce96 --- /dev/null +++ b/third_party/rust/nix/test/sys/test_statfs.rs @@ -0,0 +1,99 @@ +use nix::sys::statfs::*; +use nix::sys::statvfs::*; +use std::fs::File; +use std::path::Path; + +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); +} + +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(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); +} + +#[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("/"); +} + +// 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("/"); +} + +// 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/third_party/rust/nix/test/sys/test_statvfs.rs b/third_party/rust/nix/test/sys/test_statvfs.rs new file mode 100644 index 0000000000..5c80965253 --- /dev/null +++ b/third_party/rust/nix/test/sys/test_statvfs.rs @@ -0,0 +1,13 @@ +use nix::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/third_party/rust/nix/test/sys/test_termios.rs b/third_party/rust/nix/test/sys/test_termios.rs index 83919378a7..35cc7ab739 100644 --- a/third_party/rust/nix/test/sys/test_termios.rs +++ b/third_party/rust/nix/test/sys/test_termios.rs @@ -4,17 +4,26 @@ use tempfile::tempfile; use nix::errno::Errno; use nix::fcntl; use nix::pty::openpty; -use nix::sys::termios::{self, tcgetattr, LocalFlags, OutputFlags}; +use nix::sys::termios::{self, tcgetattr, BaudRate, LocalFlags, OutputFlags}; use nix::unistd::{read, write}; /// Helper function analogous to `std::io::Write::write_all`, but for `Fd`s fn write_all<Fd: AsFd>(f: Fd, buf: &[u8]) { let mut len = 0; while len < buf.len() { - len += write(f.as_fd().as_raw_fd(), &buf[len..]).unwrap(); + len += write(f.as_fd(), &buf[len..]).unwrap(); } } +#[test] +fn test_baudrate_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"); +} + // Test tcgetattr on a terminal #[test] fn test_tcgetattr_pty() { diff --git a/third_party/rust/nix/test/sys/test_time.rs b/third_party/rust/nix/test/sys/test_time.rs new file mode 100644 index 0000000000..0510225a92 --- /dev/null +++ b/third_party/rust/nix/test/sys/test_time.rs @@ -0,0 +1,91 @@ +use nix::sys::time::{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/third_party/rust/nix/test/test_timer.rs b/third_party/rust/nix/test/sys/test_timer.rs index ffd146867b..ffd146867b 100644 --- a/third_party/rust/nix/test/test_timer.rs +++ b/third_party/rust/nix/test/sys/test_timer.rs diff --git a/third_party/rust/nix/test/sys/test_uio.rs b/third_party/rust/nix/test/sys/test_uio.rs index fc09465f19..d035a7bb04 100644 --- a/third_party/rust/nix/test/sys/test_uio.rs +++ b/third_party/rust/nix/test/sys/test_uio.rs @@ -4,7 +4,7 @@ use rand::distributions::Alphanumeric; use rand::{thread_rng, Rng}; use std::fs::OpenOptions; use std::io::IoSlice; -use std::os::unix::io::{FromRawFd, OwnedFd}; +use std::os::unix::io::AsRawFd; use std::{cmp, iter}; #[cfg(not(target_os = "redox"))] @@ -44,22 +44,17 @@ fn test_writev() { // FileDesc will close its filedesc (reader). let mut read_buf: Vec<u8> = iter::repeat(0u8).take(128 * 16).collect(); - // Temporary workaround to cope with the existing RawFd pipe(2), should be - // removed when pipe(2) becomes I/O-safe. - let writer = unsafe { OwnedFd::from_raw_fd(writer) }; - // 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_res = read(reader.as_raw_fd(), &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(reader).expect("closed reader"); } #[test] @@ -92,10 +87,6 @@ fn test_readv() { // Blocking io, should write all data. write(writer, &to_write).expect("write failed"); - // Temporary workaround to cope with the existing RawFd pipe(2), should be - // removed when pipe(2) becomes I/O-safe. - let reader = unsafe { OwnedFd::from_raw_fd(reader) }; - let read = readv(&reader, &mut iovecs[..]).expect("read failed"); // Check whether we've read all data assert_eq!(to_write.len(), read); @@ -108,7 +99,6 @@ fn test_readv() { assert_eq!(read_buf.len(), to_write.len()); // Check equality of written and read data assert_eq!(&read_buf, &to_write); - close(writer).expect("couldn't close writer"); } #[test] @@ -150,7 +140,11 @@ fn test_pread() { } #[test] -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +#[cfg(not(any( + target_os = "redox", + target_os = "haiku", + target_os = "solaris" +)))] fn test_pwritev() { use std::io::Read; @@ -185,7 +179,11 @@ fn test_pwritev() { } #[test] -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +#[cfg(not(any( + target_os = "redox", + target_os = "haiku", + target_os = "solaris" +)))] fn test_preadv() { use std::io::Write; @@ -230,6 +228,7 @@ fn test_process_vm_readv() { use nix::sys::signal::*; use nix::sys::wait::*; use nix::unistd::ForkResult::*; + use std::os::unix::io::AsRawFd; require_capability!("test_process_vm_readv", CAP_SYS_PTRACE); let _m = crate::FORK_MTX.lock(); @@ -241,10 +240,10 @@ fn test_process_vm_readv() { let (r, w) = pipe().unwrap(); match unsafe { fork() }.expect("Error: Fork Failed") { Parent { child } => { - close(w).unwrap(); + drop(w); // wait for child - read(r, &mut [0u8]).unwrap(); - close(r).unwrap(); + read(r.as_raw_fd(), &mut [0u8]).unwrap(); + drop(r); let ptr = vector.as_ptr() as usize; let remote_iov = RemoteIoVec { base: ptr, len: 5 }; @@ -263,12 +262,11 @@ fn test_process_vm_readv() { assert_eq!(20u8, buf.iter().sum()); } Child => { - let _ = close(r); + drop(r); for i in &mut vector { *i += 1; } let _ = write(w, b"\0"); - let _ = close(w); loop { pause(); } diff --git a/third_party/rust/nix/test/sys/test_utsname.rs b/third_party/rust/nix/test/sys/test_utsname.rs new file mode 100644 index 0000000000..8f84ac074f --- /dev/null +++ b/third_party/rust/nix/test/sys/test_utsname.rs @@ -0,0 +1,17 @@ +#[cfg(target_os = "linux")] +#[test] +pub fn test_uname_linux() { + assert_eq!(nix::sys::utsname::uname().unwrap().sysname(), "Linux"); +} + +#[cfg(apple_targets)] +#[test] +pub fn test_uname_darwin() { + assert_eq!(nix::sys::utsname::uname().unwrap().sysname(), "Darwin"); +} + +#[cfg(target_os = "freebsd")] +#[test] +pub fn test_uname_freebsd() { + assert_eq!(nix::sys::utsname::uname().unwrap().sysname(), "FreeBSD"); +} diff --git a/third_party/rust/nix/test/sys/test_wait.rs b/third_party/rust/nix/test/sys/test_wait.rs index d472f1ec19..365b0165f8 100644 --- a/third_party/rust/nix/test/sys/test_wait.rs +++ b/third_party/rust/nix/test/sys/test_wait.rs @@ -33,7 +33,12 @@ fn test_wait_signal() { //target_os = "haiku", all(target_os = "linux", not(target_env = "uclibc")), ))] -#[cfg(not(any(target_arch = "mips", target_arch = "mips64")))] +#[cfg(not(any( + target_arch = "mips", + target_arch = "mips32r6", + target_arch = "mips64", + target_arch = "mips64r6" +)))] fn test_waitid_signal() { let _m = crate::FORK_MTX.lock(); @@ -76,7 +81,12 @@ fn test_wait_exit() { target_os = "haiku", all(target_os = "linux", not(target_env = "uclibc")), ))] -#[cfg(not(any(target_arch = "mips", target_arch = "mips64")))] +#[cfg(not(any( + target_arch = "mips", + target_arch = "mips32r6", + target_arch = "mips64", + target_arch = "mips64r6" +)))] fn test_waitid_exit() { let _m = crate::FORK_MTX.lock(); @@ -140,7 +150,7 @@ fn test_waitid_pid() { } } -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] // FIXME: qemu-user doesn't implement ptrace on most arches #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] mod ptrace { diff --git a/third_party/rust/nix/test/test.rs b/third_party/rust/nix/test/test.rs index 7e73bb3056..c7231426c2 100644 --- a/third_party/rust/nix/test/test.rs +++ b/third_party/rust/nix/test/test.rs @@ -7,12 +7,14 @@ mod common; mod sys; #[cfg(not(target_os = "redox"))] mod test_dir; +mod test_errno; mod test_fcntl; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] mod test_kmod; +#[cfg(target_os = "linux")] +mod test_mount; #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", + freebsdlike, target_os = "fushsia", target_os = "linux", target_os = "netbsd" @@ -30,36 +32,16 @@ mod test_poll; target_os = "haiku" )))] mod test_pty; -mod test_resource; #[cfg(any( - target_os = "android", + linux_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" -))] +#[cfg(any(linux_android, freebsdlike, apple_targets, solarish))] 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}; diff --git a/third_party/rust/nix/test/test_dir.rs b/third_party/rust/nix/test/test_dir.rs index 2af4aa5c0a..24ecd6963e 100644 --- a/third_party/rust/nix/test/test_dir.rs +++ b/third_party/rust/nix/test/test_dir.rs @@ -6,10 +6,10 @@ use tempfile::tempdir; #[cfg(test)] fn flags() -> OFlag { - #[cfg(target_os = "illumos")] + #[cfg(solarish)] let f = OFlag::O_RDONLY | OFlag::O_CLOEXEC; - #[cfg(not(target_os = "illumos"))] + #[cfg(not(solarish))] let f = OFlag::O_RDONLY | OFlag::O_CLOEXEC | OFlag::O_DIRECTORY; f diff --git a/third_party/rust/nix/test/test_errno.rs b/third_party/rust/nix/test/test_errno.rs new file mode 100644 index 0000000000..750fc924ff --- /dev/null +++ b/third_party/rust/nix/test/test_errno.rs @@ -0,0 +1,16 @@ +use nix::errno::Errno; + +#[test] +fn errno_set_and_read() { + Errno::ENFILE.set(); + assert_eq!(Errno::last(), Errno::ENFILE); +} + +#[test] +fn errno_set_and_clear() { + Errno::ENFILE.set(); + assert_eq!(Errno::last(), Errno::ENFILE); + + Errno::clear(); + assert_eq!(Errno::last(), Errno::from_raw(0)); +} diff --git a/third_party/rust/nix/test/test_fcntl.rs b/third_party/rust/nix/test/test_fcntl.rs index 5fef04ba9b..6572e8af8d 100644 --- a/third_party/rust/nix/test/test_fcntl.rs +++ b/third_party/rust/nix/test/test_fcntl.rs @@ -42,7 +42,7 @@ fn test_openat() { open(tmp.path().parent().unwrap(), OFlag::empty(), Mode::empty()) .unwrap(); let fd = openat( - dirfd, + Some(dirfd), tmp.path().file_name().unwrap(), OFlag::O_RDONLY, Mode::empty(), @@ -222,7 +222,7 @@ fn test_readlink() { assert_eq!(readlink(&dst).unwrap().to_str().unwrap(), expected_dir); assert_eq!( - readlinkat(dirfd, "b").unwrap().to_str().unwrap(), + readlinkat(Some(dirfd), "b").unwrap().to_str().unwrap(), expected_dir ); } @@ -234,10 +234,9 @@ fn test_readlink() { /// The from_offset should be updated by the call to reflect /// the 3 bytes read (6). #[cfg(any( - target_os = "linux", + linux_android, // Not available until FreeBSD 13.0 all(target_os = "freebsd", fbsd14), - target_os = "android" ))] #[test] // QEMU does not support copy_file_range. Skip under qemu @@ -272,7 +271,7 @@ fn test_copy_file_range() { assert_eq!(from_offset, 6); } -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] mod linux_android { use libc::loff_t; use std::io::prelude::*; @@ -280,7 +279,7 @@ mod linux_android { use std::os::unix::prelude::*; use nix::fcntl::*; - use nix::unistd::{close, pipe, read, write}; + use nix::unistd::{pipe, read, write}; use tempfile::tempfile; #[cfg(target_os = "linux")] @@ -299,7 +298,7 @@ mod linux_android { let res = splice( tmp.as_raw_fd(), Some(&mut offset), - wr, + wr.as_raw_fd(), None, 2, SpliceFFlags::empty(), @@ -309,12 +308,9 @@ mod linux_android { assert_eq!(2, res); let mut buf = [0u8; 1024]; - assert_eq!(2, read(rd, &mut buf).unwrap()); + assert_eq!(2, read(rd.as_raw_fd(), &mut buf).unwrap()); assert_eq!(b"f1", &buf[0..2]); assert_eq!(7, offset); - - close(rd).unwrap(); - close(wr).unwrap(); } #[test] @@ -323,24 +319,21 @@ mod linux_android { let (rd2, wr2) = pipe().unwrap(); write(wr1, b"abc").unwrap(); - let res = tee(rd1, wr2, 2, SpliceFFlags::empty()).unwrap(); + let res = + tee(rd1.as_raw_fd(), wr2.as_raw_fd(), 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!(2, read(rd2.as_raw_fd(), &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!(3, read(rd1.as_raw_fd(), &mut buf).unwrap()); assert_eq!(b"abc", &buf[0..3]); - - close(rd1).unwrap(); - close(wr1).unwrap(); - close(rd2).unwrap(); - close(wr2).unwrap(); } #[test] @@ -351,17 +344,15 @@ mod linux_android { let buf2 = b"defghi"; let iovecs = [IoSlice::new(&buf1[0..3]), IoSlice::new(&buf2[0..3])]; - let res = vmsplice(wr, &iovecs[..], SpliceFFlags::empty()).unwrap(); + let res = vmsplice(wr.as_raw_fd(), &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!(6, read(rd.as_raw_fd(), &mut buf).unwrap()); assert_eq!(b"abcdef", &buf[0..6]); - - close(rd).unwrap(); - close(wr).unwrap(); } #[cfg(target_os = "linux")] @@ -481,8 +472,7 @@ mod linux_android { } #[cfg(any( - target_os = "linux", - target_os = "android", + linux_android, target_os = "emscripten", target_os = "fuchsia", target_os = "wasi", @@ -494,7 +484,7 @@ mod test_posix_fadvise { use nix::errno::Errno; use nix::fcntl::*; use nix::unistd::pipe; - use std::os::unix::io::{AsRawFd, RawFd}; + use std::os::unix::io::AsRawFd; use tempfile::NamedTempFile; #[test] @@ -509,7 +499,7 @@ mod test_posix_fadvise { fn test_errno() { let (rd, _wr) = pipe().unwrap(); let res = posix_fadvise( - rd as RawFd, + rd.as_raw_fd(), 0, 100, PosixFadviseAdvice::POSIX_FADV_WILLNEED, @@ -519,23 +509,18 @@ mod test_posix_fadvise { } #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "dragonfly", + linux_android, + freebsdlike, 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 std::{io::Read, os::unix::io::AsRawFd}; use tempfile::NamedTempFile; #[test] @@ -565,10 +550,133 @@ mod test_posix_fallocate { #[test] fn errno() { let (rd, _wr) = pipe().unwrap(); - let err = posix_fallocate(rd as RawFd, 0, 100).unwrap_err(); + let err = posix_fallocate(rd.as_raw_fd(), 0, 100).unwrap_err(); match err { Errno::EINVAL | Errno::ENODEV | Errno::ESPIPE | Errno::EBADF => (), errno => panic!("unexpected errno {errno}",), } } } + +#[cfg(any(target_os = "dragonfly", target_os = "netbsd", apple_targets))] +#[test] +fn test_f_get_path() { + use nix::fcntl::*; + use std::{os::unix::io::AsRawFd, path::PathBuf}; + + let tmp = NamedTempFile::new().unwrap(); + let fd = tmp.as_raw_fd(); + let mut path = PathBuf::new(); + let res = + fcntl(fd, FcntlArg::F_GETPATH(&mut path)).expect("get path failed"); + assert_ne!(res, -1); + assert_eq!( + path.as_path().canonicalize().unwrap(), + tmp.path().canonicalize().unwrap() + ); +} + +#[cfg(apple_targets)] +#[test] +fn test_f_get_path_nofirmlink() { + use nix::fcntl::*; + use std::{os::unix::io::AsRawFd, path::PathBuf}; + + let tmp = NamedTempFile::new().unwrap(); + let fd = tmp.as_raw_fd(); + let mut path = PathBuf::new(); + let res = fcntl(fd, FcntlArg::F_GETPATH_NOFIRMLINK(&mut path)) + .expect("get path failed"); + let mut tmpstr = String::from("/System/Volumes/Data"); + tmpstr.push_str( + &tmp.path() + .canonicalize() + .unwrap() + .into_os_string() + .into_string() + .unwrap(), + ); + assert_ne!(res, -1); + assert_eq!( + path.as_path() + .canonicalize() + .unwrap() + .into_os_string() + .into_string() + .unwrap(), + tmpstr + ); +} + +#[cfg(all(target_os = "freebsd", target_arch = "x86_64"))] +#[test] +fn test_f_kinfo() { + use nix::fcntl::*; + use std::{os::unix::io::AsRawFd, path::PathBuf}; + + let tmp = NamedTempFile::new().unwrap(); + // With TMPDIR set with UFS, the vnode name is not entered + // into the name cache thus path is always empty. + // Therefore, we reopen the tempfile a second time for the test + // to pass. + let tmp2 = File::open(tmp.path()).unwrap(); + let fd = tmp2.as_raw_fd(); + let mut path = PathBuf::new(); + let res = fcntl(fd, FcntlArg::F_KINFO(&mut path)).expect("get path failed"); + assert_ne!(res, -1); + assert_eq!(path, tmp.path()); +} + +/// Test `Flock` and associated functions. +/// +#[cfg(not(any(target_os = "redox", target_os = "solaris")))] +mod test_flock { + use nix::fcntl::*; + use tempfile::NamedTempFile; + + /// Verify that `Flock::lock()` correctly obtains a lock, and subsequently unlocks upon drop. + #[test] + fn verify_lock_and_drop() { + // Get 2 `File` handles to same underlying file. + let file1 = NamedTempFile::new().unwrap(); + let file2 = file1.reopen().unwrap(); + let file1 = file1.into_file(); + + // Lock first handle + let lock1 = Flock::lock(file1, FlockArg::LockExclusive).unwrap(); + + // Attempt to lock second handle + let file2 = match Flock::lock(file2, FlockArg::LockExclusiveNonblock) { + Ok(_) => panic!("Expected second exclusive lock to fail."), + Err((f, _)) => f, + }; + + // Drop first lock + std::mem::drop(lock1); + + // Attempt to lock second handle again (but successfully) + if Flock::lock(file2, FlockArg::LockExclusiveNonblock).is_err() { + panic!("Expected locking to be successful."); + } + } + + /// Verify that `Flock::unlock()` correctly obtains unlocks. + #[test] + fn verify_unlock() { + // Get 2 `File` handles to same underlying file. + let file1 = NamedTempFile::new().unwrap(); + let file2 = file1.reopen().unwrap(); + let file1 = file1.into_file(); + + // Lock first handle + let lock1 = Flock::lock(file1, FlockArg::LockExclusive).unwrap(); + + // Unlock and retain file so any erroneous flocks also remain present. + let _file1 = lock1.unlock().unwrap(); + + // Attempt to lock second handle. + if Flock::lock(file2, FlockArg::LockExclusiveNonblock).is_err() { + panic!("Expected locking to be successful."); + } + } +} diff --git a/third_party/rust/nix/test/test_mount.rs b/third_party/rust/nix/test/test_mount.rs index 5cf00408e8..a4f0903dba 100644 --- a/third_party/rust/nix/test/test_mount.rs +++ b/third_party/rust/nix/test/test_mount.rs @@ -1,267 +1,183 @@ -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 +use std::fs::{self, File}; +use std::io::{Read, Write}; +use std::os::unix::fs::OpenOptionsExt; +use std::os::unix::fs::PermissionsExt; +use std::process::Command; + +use libc::{EACCES, EROFS}; + +use nix::mount::{mount, umount, MsFlags}; +use nix::sys::stat::{self, Mode}; + +use crate::*; + +static SCRIPT_CONTENTS: &[u8] = b"#!/bin/sh exit 23"; - const EXPECTED_STATUS: i32 = 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(); +const NONE: Option<&'static [u8]> = None; - mount( - NONE, - tempdir.path(), - Some(b"tmpfs".as_ref()), - MsFlags::empty(), - NONE, - ) - .unwrap_or_else(|e| panic!("mount failed: {e}")); +#[test] +fn test_mount_tmpfs_without_flags_allows_rwx() { + require_capability!( + "test_mount_tmpfs_without_flags_allows_rwx", + CAP_SYS_ADMIN + ); + 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) + .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")) + ); - let test_path = tempdir.path().join("test"); + umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {e}")); +} - // 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}")); +#[test] +fn test_mount_rdonly_disallows_write() { + require_capability!("test_mount_rdonly_disallows_write", CAP_SYS_ADMIN); + 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() + ); - // 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}")); - } + umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {e}")); +} - pub fn test_mount_rdonly_disallows_write() { - let tempdir = tempfile::tempdir().unwrap(); +#[test] +fn test_mount_noexec_disallows_exec() { + require_capability!("test_mount_noexec_disallows_exec", CAP_SYS_ADMIN); + 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}")), + ); - mount( - NONE, - tempdir.path(), - Some(b"tmpfs".as_ref()), - MsFlags::MS_RDONLY, - NONE, - ) - .unwrap_or_else(|e| panic!("mount 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() + ); - // 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}")); +} - umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {e}")); - } +#[test] +fn test_mount_bind() { + require_capability!("test_mount_bind", CAP_SYS_ADMIN); + let tempdir = tempfile::tempdir().unwrap(); + let file_name = "test"; - pub fn test_mount_noexec_disallows_exec() { - let tempdir = tempfile::tempdir().unwrap(); + { + let mount_point = tempfile::tempdir().unwrap(); mount( + Some(tempdir.path()), + mount_point.path(), NONE, - tempdir.path(), - Some(b"tmpfs".as_ref()), - MsFlags::MS_NOEXEC, + MsFlags::MS_BIND, 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) + .open(mount_point.path().join(file_name)) .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}")); + umount(mount_point.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); - } + // Verify the file written in the mount shows up in source directory, even + // after unmounting. - 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: {e}. Are unprivileged user namespaces available?").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 {uid} 1\n").as_bytes())) - .unwrap_or_else(|e| panic!("could not write uid map: {e}")); - } + 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); } - -// 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/third_party/rust/nix/test/test_mq.rs b/third_party/rust/nix/test/test_mq.rs index 1fd8929c17..874a72b44d 100644 --- a/third_party/rust/nix/test/test_mq.rs +++ b/third_party/rust/nix/test/test_mq.rs @@ -112,7 +112,15 @@ fn test_mq_getattr() { // FIXME: Fix failures for mips in QEMU #[test] #[cfg_attr( - all(qemu, any(target_arch = "mips", target_arch = "mips64")), + all( + qemu, + any( + target_arch = "mips", + target_arch = "mips32r6", + target_arch = "mips64", + target_arch = "mips64r6" + ) + ), ignore )] fn test_mq_setattr() { @@ -162,7 +170,15 @@ fn test_mq_setattr() { // FIXME: Fix failures for mips in QEMU #[test] #[cfg_attr( - all(qemu, any(target_arch = "mips", target_arch = "mips64")), + all( + qemu, + any( + target_arch = "mips", + target_arch = "mips32r6", + target_arch = "mips64", + target_arch = "mips64r6" + ) + ), ignore )] fn test_mq_set_nonblocking() { diff --git a/third_party/rust/nix/test/test_net.rs b/third_party/rust/nix/test/test_net.rs index c44655a4c9..faba8503fe 100644 --- a/third_party/rust/nix/test/test_net.rs +++ b/third_party/rust/nix/test/test_net.rs @@ -1,13 +1,9 @@ use nix::net::if_::*; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] const LOOPBACK: &[u8] = b"lo"; -#[cfg(not(any( - target_os = "android", - target_os = "linux", - target_os = "haiku" -)))] +#[cfg(not(any(linux_android, target_os = "haiku")))] const LOOPBACK: &[u8] = b"lo0"; #[cfg(target_os = "haiku")] diff --git a/third_party/rust/nix/test/test_poll.rs b/third_party/rust/nix/test/test_poll.rs index 045ccd3df1..fcb325494e 100644 --- a/third_party/rust/nix/test/test_poll.rs +++ b/third_party/rust/nix/test/test_poll.rs @@ -1,9 +1,9 @@ use nix::{ errno::Errno, - poll::{poll, PollFd, PollFlags}, - unistd::{close, pipe, write}, + poll::{poll, PollFd, PollFlags, PollTimeout}, + unistd::{pipe, write}, }; -use std::os::unix::io::{BorrowedFd, FromRawFd, OwnedFd}; +use std::os::unix::io::{AsFd, BorrowedFd}; macro_rules! loop_while_eintr { ($poll_expr: expr) => { @@ -20,32 +20,25 @@ macro_rules! loop_while_eintr { #[test] fn test_poll() { let (r, w) = pipe().unwrap(); - let r = unsafe { OwnedFd::from_raw_fd(r) }; - let mut fds = [PollFd::new(&r, PollFlags::POLLIN)]; + let mut fds = [PollFd::new(r.as_fd(), PollFlags::POLLIN)]; // Poll an idle pipe. Should timeout - let nfds = loop_while_eintr!(poll(&mut fds, 100)); + let nfds = loop_while_eintr!(poll(&mut fds, PollTimeout::from(100u8))); assert_eq!(nfds, 0); assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN)); - write(w, b".").unwrap(); + write(&w, b".").unwrap(); // Poll a readable pipe. Should return an event. - let nfds = poll(&mut fds, 100).unwrap(); + let nfds = poll(&mut fds, PollTimeout::from(100u8)).unwrap(); assert_eq!(nfds, 1); assert!(fds[0].revents().unwrap().contains(PollFlags::POLLIN)); - close(w).unwrap(); } // 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" -))] +#[cfg(any(linux_android, freebsdlike))] #[test] fn test_ppoll() { use nix::poll::ppoll; @@ -54,8 +47,7 @@ fn test_ppoll() { let timeout = TimeSpec::milliseconds(1); let (r, w) = pipe().unwrap(); - let r = unsafe { OwnedFd::from_raw_fd(r) }; - let mut fds = [PollFd::new(&r, PollFlags::POLLIN)]; + let mut fds = [PollFd::new(r.as_fd(), PollFlags::POLLIN)]; // Poll an idle pipe. Should timeout let sigset = SigSet::empty(); @@ -63,19 +55,18 @@ fn test_ppoll() { assert_eq!(nfds, 0); assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN)); - write(w, b".").unwrap(); + 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)); - close(w).unwrap(); } #[test] fn test_pollfd_events() { let fd_zero = unsafe { BorrowedFd::borrow_raw(0) }; - let mut pfd = PollFd::new(&fd_zero, PollFlags::POLLIN); + let mut pfd = PollFd::new(fd_zero.as_fd(), PollFlags::POLLIN); assert_eq!(pfd.events(), PollFlags::POLLIN); pfd.set_events(PollFlags::POLLOUT); assert_eq!(pfd.events(), PollFlags::POLLOUT); diff --git a/third_party/rust/nix/test/test_pty.rs b/third_party/rust/nix/test/test_pty.rs index 4cc6620c3c..368ec129b0 100644 --- a/third_party/rust/nix/test/test_pty.rs +++ b/third_party/rust/nix/test/test_pty.rs @@ -1,9 +1,9 @@ use std::fs::File; -use std::io::{Read, Write}; +use std::io::{stdout, Read, Write}; use std::os::unix::prelude::*; use std::path::Path; -use libc::{_exit, STDOUT_FILENO}; +use libc::_exit; use nix::fcntl::{open, OFlag}; use nix::pty::*; use nix::sys::stat; @@ -12,7 +12,7 @@ use nix::unistd::{pause, write}; /// Test equivalence of `ptsname` and `ptsname_r` #[test] -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] fn test_ptsname_equivalence() { let _m = crate::PTSNAME_MTX.lock(); @@ -29,7 +29,7 @@ fn test_ptsname_equivalence() { /// 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"))] +#[cfg(linux_android)] fn test_ptsname_copy() { let _m = crate::PTSNAME_MTX.lock(); @@ -47,7 +47,7 @@ fn test_ptsname_copy() { /// Test data copying of `ptsname_r` #[test] -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] fn test_ptsname_r_copy() { // Open a new PTTY master let master_fd = posix_openpt(OFlag::O_RDWR).unwrap(); @@ -61,7 +61,7 @@ fn test_ptsname_r_copy() { /// Test that `ptsname` returns different names for different devices #[test] -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] fn test_ptsname_unique() { let _m = crate::PTSNAME_MTX.lock(); @@ -96,7 +96,7 @@ fn open_ptty_pair() -> (PtyMaster, File) { open(Path::new(&slave_name), OFlag::O_RDWR, stat::Mode::empty()) .unwrap(); - #[cfg(target_os = "illumos")] + #[cfg(solarish)] // TODO: rewrite using ioctl! #[allow(clippy::comparison_chain)] { @@ -185,7 +185,7 @@ fn test_openpty() { // Writing to one should be readable on the other one let string = "foofoofoo\n"; let mut buf = [0u8; 10]; - write(pty.master.as_raw_fd(), string.as_bytes()).unwrap(); + write(&pty.master, string.as_bytes()).unwrap(); crate::read_exact(&pty.slave, &mut buf); assert_eq!(&buf, string.as_bytes()); @@ -199,7 +199,7 @@ fn test_openpty() { let string2 = "barbarbarbar\n"; let echoed_string2 = "barbarbarbar\r\n"; let mut buf = [0u8; 14]; - write(pty.slave.as_raw_fd(), string2.as_bytes()).unwrap(); + write(&pty.slave, string2.as_bytes()).unwrap(); crate::read_exact(&pty.master, &mut buf); assert_eq!(&buf, echoed_string2.as_bytes()); @@ -224,7 +224,7 @@ fn test_openpty_with_termios() { // Writing to one should be readable on the other one let string = "foofoofoo\n"; let mut buf = [0u8; 10]; - write(pty.master.as_raw_fd(), string.as_bytes()).unwrap(); + write(&pty.master, string.as_bytes()).unwrap(); crate::read_exact(&pty.slave, &mut buf); assert_eq!(&buf, string.as_bytes()); @@ -237,7 +237,7 @@ fn test_openpty_with_termios() { let string2 = "barbarbarbar\n"; let echoed_string2 = "barbarbarbar\n"; let mut buf = [0u8; 13]; - write(pty.slave.as_raw_fd(), string2.as_bytes()).unwrap(); + write(&pty.slave, string2.as_bytes()).unwrap(); crate::read_exact(&pty.master, &mut buf); assert_eq!(&buf, echoed_string2.as_bytes()); @@ -258,7 +258,7 @@ fn test_forkpty() { let pty = unsafe { forkpty(None, None).unwrap() }; match pty.fork_result { Child => { - write(STDOUT_FILENO, string.as_bytes()).unwrap(); + write(stdout(), string.as_bytes()).unwrap(); pause(); // we need the child to stay alive until the parent calls read unsafe { _exit(0); diff --git a/third_party/rust/nix/test/test_sendfile.rs b/third_party/rust/nix/test/test_sendfile.rs index b85e030fd3..6333bf8662 100644 --- a/third_party/rust/nix/test/test_sendfile.rs +++ b/third_party/rust/nix/test/test_sendfile.rs @@ -1,21 +1,20 @@ use std::io::prelude::*; -#[cfg(any(target_os = "android", target_os = "linux"))] -use std::os::unix::io::{FromRawFd, OwnedFd}; 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"))] { + if #[cfg(linux_android)] { + use nix::unistd::{pipe, read}; + use std::os::unix::io::AsRawFd; + } else if #[cfg(any(freebsdlike, apple_targets, solarish))] { use std::net::Shutdown; use std::os::unix::net::UnixStream; } } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[test] fn test_sendfile_linux() { const CONTENTS: &[u8] = b"abcdef123456"; @@ -24,21 +23,14 @@ fn test_sendfile_linux() { let (rd, wr) = pipe().unwrap(); let mut offset: off_t = 5; - // The construct of this `OwnedFd` is a temporary workaround, when `pipe(2)` - // becomes I/O-safe: - // pub fn pipe() -> std::result::Result<(OwnedFd, OwnedFd), Error> - // then it is no longer needed. - let wr = unsafe { OwnedFd::from_raw_fd(wr) }; let res = sendfile(&wr, &tmp, Some(&mut offset), 2).unwrap(); assert_eq!(2, res); let mut buf = [0u8; 1024]; - assert_eq!(2, read(rd, &mut buf).unwrap()); + assert_eq!(2, read(rd.as_raw_fd(), &mut buf).unwrap()); assert_eq!(b"f1", &buf[0..2]); assert_eq!(7, offset); - - close(rd).unwrap(); } #[cfg(target_os = "linux")] @@ -50,21 +42,14 @@ fn test_sendfile64_linux() { let (rd, wr) = pipe().unwrap(); let mut offset: libc::off64_t = 5; - // The construct of this `OwnedFd` is a temporary workaround, when `pipe(2)` - // becomes I/O-safe: - // pub fn pipe() -> std::result::Result<(OwnedFd, OwnedFd), Error> - // then it is no longer needed. - let wr = unsafe { OwnedFd::from_raw_fd(wr) }; let res = sendfile64(&wr, &tmp, Some(&mut offset), 2).unwrap(); assert_eq!(2, res); let mut buf = [0u8; 1024]; - assert_eq!(2, read(rd, &mut buf).unwrap()); + assert_eq!(2, read(rd.as_raw_fd(), &mut buf).unwrap()); assert_eq!(b"f1", &buf[0..2]); assert_eq!(7, offset); - - close(rd).unwrap(); } #[cfg(target_os = "freebsd")] @@ -167,7 +152,7 @@ fn test_sendfile_dragonfly() { assert_eq!(expected_string, read_string); } -#[cfg(any(target_os = "ios", target_os = "macos"))] +#[cfg(apple_targets)] #[test] fn test_sendfile_darwin() { // Declare the content @@ -215,3 +200,62 @@ fn test_sendfile_darwin() { assert_eq!(bytes_written as usize, bytes_read); assert_eq!(expected_string, read_string); } + +#[cfg(solarish)] +#[test] +fn test_sendfilev() { + use std::os::fd::AsFd; + // Declare the content + let header_strings = + ["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"]; + let body = "Xabcdef123456"; + let body_offset = 1usize; + let trailer_strings = ["\n", "Served by Make Believe\n"]; + + // Write data to files + let mut header_data = tempfile().unwrap(); + header_data + .write_all(header_strings.concat().as_bytes()) + .unwrap(); + let mut body_data = tempfile().unwrap(); + body_data.write_all(body.as_bytes()).unwrap(); + let mut trailer_data = tempfile().unwrap(); + trailer_data + .write_all(trailer_strings.concat().as_bytes()) + .unwrap(); + let (mut rd, wr) = UnixStream::pair().unwrap(); + let vec: &[SendfileVec] = &[ + SendfileVec::new( + header_data.as_fd(), + 0, + header_strings.iter().map(|s| s.len()).sum(), + ), + SendfileVec::new( + body_data.as_fd(), + body_offset as off_t, + body.len() - body_offset, + ), + SendfileVec::new( + trailer_data.as_fd(), + 0, + trailer_strings.iter().map(|s| s.len()).sum(), + ), + ]; + + let (res, bytes_written) = sendfilev(&wr, vec); + 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, 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, bytes_read); + assert_eq!(expected_string, read_string); +} diff --git a/third_party/rust/nix/test/test_stat.rs b/third_party/rust/nix/test/test_stat.rs index 55f15c0771..386f1084cc 100644 --- a/third_party/rust/nix/test/test_stat.rs +++ b/third_party/rust/nix/test/test_stat.rs @@ -21,8 +21,7 @@ use nix::errno::Errno; use nix::fcntl; #[cfg(any( target_os = "linux", - target_os = "ios", - target_os = "macos", + apple_targets, target_os = "freebsd", target_os = "netbsd" ))] @@ -117,7 +116,7 @@ fn test_fstatat() { fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()); let result = - stat::fstatat(dirfd.unwrap(), &filename, fcntl::AtFlags::empty()); + stat::fstatat(Some(dirfd.unwrap()), &filename, fcntl::AtFlags::empty()); assert_stat_results(result); } @@ -235,8 +234,7 @@ fn test_utimes() { #[test] #[cfg(any( target_os = "linux", - target_os = "ios", - target_os = "macos", + apple_targets, target_os = "freebsd", target_os = "netbsd" ))] @@ -323,7 +321,7 @@ fn test_mkdirat_success_path() { let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) .unwrap(); - mkdirat(dirfd, filename, Mode::S_IRWXU).expect("mkdirat failed"); + mkdirat(Some(dirfd), filename, Mode::S_IRWXU).expect("mkdirat failed"); assert!(Path::exists(&tempdir.path().join(filename))); } @@ -337,7 +335,7 @@ fn test_mkdirat_success_mode() { let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) .unwrap(); - mkdirat(dirfd, filename, Mode::S_IRWXU).expect("mkdirat failed"); + mkdirat(Some(dirfd), filename, Mode::S_IRWXU).expect("mkdirat failed"); let permissions = fs::metadata(tempdir.path().join(filename)) .unwrap() .permissions(); @@ -357,16 +355,14 @@ fn test_mkdirat_fail() { stat::Mode::empty(), ) .unwrap(); - let result = mkdirat(dirfd, filename, Mode::S_IRWXU).unwrap_err(); + let result = mkdirat(Some(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", + freebsdlike, + apple_targets, target_os = "haiku", target_os = "redox" )))] @@ -384,11 +380,9 @@ fn test_mknod() { #[test] #[cfg(not(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", - target_os = "macos", + solarish, + freebsdlike, + apple_targets, target_os = "haiku", target_os = "redox" )))] @@ -402,7 +396,7 @@ fn test_mknodat() { let target_dir = Dir::open(tempdir.path(), OFlag::O_DIRECTORY, Mode::S_IRWXU).unwrap(); mknodat( - target_dir.as_raw_fd(), + Some(target_dir.as_raw_fd()), file_name, SFlag::S_IFREG, Mode::S_IRWXU, @@ -410,7 +404,7 @@ fn test_mknodat() { ) .unwrap(); let mode = fstatat( - target_dir.as_raw_fd(), + Some(target_dir.as_raw_fd()), file_name, AtFlags::AT_SYMLINK_NOFOLLOW, ) @@ -419,3 +413,75 @@ fn test_mknodat() { assert_eq!(mode & libc::S_IFREG, libc::S_IFREG); assert_eq!(mode & libc::S_IRWXU, libc::S_IRWXU); } + +#[test] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +fn test_futimens_unchanged() { + 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(); + + let old_atime = fs::metadata(fullpath.as_path()) + .unwrap() + .accessed() + .unwrap(); + let old_mtime = fs::metadata(fullpath.as_path()) + .unwrap() + .modified() + .unwrap(); + + futimens(fd, &TimeSpec::UTIME_OMIT, &TimeSpec::UTIME_OMIT).unwrap(); + + let new_atime = fs::metadata(fullpath.as_path()) + .unwrap() + .accessed() + .unwrap(); + let new_mtime = fs::metadata(fullpath.as_path()) + .unwrap() + .modified() + .unwrap(); + assert_eq!(old_atime, new_atime); + assert_eq!(old_mtime, new_mtime); +} + +#[test] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +fn test_utimensat_unchanged() { + 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(); + + let old_atime = fs::metadata(fullpath.as_path()) + .unwrap() + .accessed() + .unwrap(); + let old_mtime = fs::metadata(fullpath.as_path()) + .unwrap() + .modified() + .unwrap(); + utimensat( + Some(dirfd), + filename, + &TimeSpec::UTIME_OMIT, + &TimeSpec::UTIME_OMIT, + UtimensatFlags::NoFollowSymlink, + ) + .unwrap(); + let new_atime = fs::metadata(fullpath.as_path()) + .unwrap() + .accessed() + .unwrap(); + let new_mtime = fs::metadata(fullpath.as_path()) + .unwrap() + .modified() + .unwrap(); + assert_eq!(old_atime, new_atime); + assert_eq!(old_mtime, new_mtime); +} diff --git a/third_party/rust/nix/test/test_time.rs b/third_party/rust/nix/test/test_time.rs index 5f76e61a2d..64c8161dbf 100644 --- a/third_party/rust/nix/test/test_time.rs +++ b/third_party/rust/nix/test/test_time.rs @@ -1,10 +1,4 @@ -#[cfg(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "linux", - target_os = "android", - target_os = "emscripten", -))] +#[cfg(any(freebsdlike, linux_android, target_os = "emscripten"))] use nix::time::clock_getcpuclockid; use nix::time::{clock_gettime, ClockId}; @@ -19,13 +13,7 @@ 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", -))] +#[cfg(any(freebsdlike, linux_android, target_os = "emscripten"))] #[test] pub fn test_clock_getcpuclockid() { let clock_id = clock_getcpuclockid(nix::unistd::Pid::this()).unwrap(); @@ -43,13 +31,7 @@ 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", -))] +#[cfg(any(freebsdlike, linux_android, target_os = "emscripten"))] #[test] pub fn test_clock_id_pid_cpu_clock_id() { ClockId::pid_cpu_clock_id(nix::unistd::Pid::this()) @@ -57,3 +39,28 @@ pub fn test_clock_id_pid_cpu_clock_id() { .unwrap() .unwrap(); } + +#[cfg(any( + linux_android, + solarish, + freebsdlike, + target_os = "netbsd", + target_os = "hurd", + target_os = "aix" +))] +#[test] +pub fn test_clock_nanosleep() { + use nix::{ + sys::time::{TimeSpec, TimeValLike}, + time::{clock_nanosleep, ClockNanosleepFlags}, + }; + + let sleep_time = TimeSpec::microseconds(1); + let res = clock_nanosleep( + ClockId::CLOCK_MONOTONIC, + ClockNanosleepFlags::empty(), + &sleep_time, + ); + let expected = TimeSpec::microseconds(0); + assert_eq!(res, Ok(expected)); +} diff --git a/third_party/rust/nix/test/test_unistd.rs b/third_party/rust/nix/test/test_unistd.rs index 10284e4127..aa2e5e56d7 100644 --- a/third_party/rust/nix/test/test_unistd.rs +++ b/third_party/rust/nix/test/test_unistd.rs @@ -67,6 +67,37 @@ fn test_fork_and_waitpid() { } #[test] +#[cfg(target_os = "freebsd")] +fn test_rfork_and_waitpid() { + let _m = crate::FORK_MTX.lock(); + + // Safe: Child only calls `_exit`, which is signal-safe + match unsafe { rfork(RforkFlags::RFPROC | RforkFlags::RFTHREAD) } + .expect("Error: Rfork 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 {s:?}, should never happen") + } + + // 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(); @@ -126,8 +157,7 @@ fn test_mkfifo_directory() { #[test] #[cfg(not(any( - target_os = "macos", - target_os = "ios", + apple_targets, target_os = "android", target_os = "redox", target_os = "haiku" @@ -147,8 +177,7 @@ fn test_mkfifoat_none() { #[test] #[cfg(not(any( - target_os = "macos", - target_os = "ios", + apple_targets, target_os = "android", target_os = "redox", target_os = "haiku" @@ -163,15 +192,15 @@ fn test_mkfifoat() { mkfifoat(Some(dirfd), mkfifoat_name, Mode::S_IRUSR).unwrap(); let stats = - stat::fstatat(dirfd, mkfifoat_name, fcntl::AtFlags::empty()).unwrap(); + stat::fstatat(Some(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", + apple_targets, target_os = "android", target_os = "redox", target_os = "haiku" @@ -186,8 +215,7 @@ fn test_mkfifoat_directory_none() { #[test] #[cfg(not(any( - target_os = "macos", - target_os = "ios", + apple_targets, target_os = "android", target_os = "redox", target_os = "haiku" @@ -197,7 +225,7 @@ fn test_mkfifoat_directory() { 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(); + stat::mkdirat(Some(dirfd), mkfifoat_dir, Mode::S_IRUSR).unwrap(); mkfifoat(Some(dirfd), mkfifoat_dir, Mode::S_IRUSR) .expect_err("assertion failed"); @@ -220,7 +248,7 @@ fn test_getsid() { assert_eq!(none_sid, pid_sid); } -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] mod linux_android { use nix::unistd::gettid; @@ -234,8 +262,7 @@ mod linux_android { #[test] // `getgroups()` and `setgroups()` do not behave as expected on Apple platforms #[cfg(not(any( - target_os = "ios", - target_os = "macos", + apple_targets, target_os = "redox", target_os = "fuchsia", target_os = "haiku" @@ -263,12 +290,11 @@ fn test_setgroups() { #[test] // `getgroups()` and `setgroups()` do not behave as expected on Apple platforms #[cfg(not(any( - target_os = "ios", - target_os = "macos", + apple_targets, target_os = "redox", target_os = "fuchsia", target_os = "haiku", - target_os = "illumos" + solarish )))] fn test_initgroups() { // Skip this test when not run as root as `initgroups()` and `setgroups()` @@ -356,7 +382,7 @@ macro_rules! execve_test_factory ( match unsafe{fork()}.unwrap() { Child => { // Make `writer` be the stdout of the new process. - dup2(writer, 1).unwrap(); + dup2(writer.as_raw_fd(), 1).unwrap(); let r = syscall(); let _ = std::io::stderr() .write_all(format!("{:?}", r).as_bytes()); @@ -370,7 +396,7 @@ macro_rules! execve_test_factory ( assert_eq!(ws, Ok(WaitStatus::Exited(child, 0))); // Read 1024 bytes. let mut buf = [0u8; 1024]; - read(reader, &mut buf).unwrap(); + read(reader.as_raw_fd(), &mut buf).unwrap(); // It should contain the things we printed using `/bin/sh`. let string = String::from_utf8_lossy(&buf); assert!(string.contains("nix!!!")); @@ -404,46 +430,44 @@ 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"))] { + } else if #[cfg(any(freebsdlike, target_os = "linux", target_os = "hurd"))] { // 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"))] { + } else if #[cfg(any(solarish, apple_targets, netbsdlike))] { 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"))] +#[cfg(any( + target_os = "haiku", + target_os = "hurd", + 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(), + Some(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(), + Some(File::open("/system/bin/").unwrap().into_raw_fd()), "./sh", AtFlags::empty()); execve_test_factory!(test_execveat_absolute, execveat, - File::open("/").unwrap().into_raw_fd(), + Some(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(), + execve_test_factory!(test_execveat_empty, execveat, Some(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(), + execve_test_factory!(test_execveat_relative, execveat, Some(File::open("/bin/").unwrap().into_raw_fd()), "./sh", AtFlags::empty()); - execve_test_factory!(test_execveat_absolute, execveat, File::open("/").unwrap().into_raw_fd(), + execve_test_factory!(test_execveat_absolute, execveat, Some(File::open("/").unwrap().into_raw_fd()), "/bin/sh", AtFlags::empty()); } } @@ -527,6 +551,8 @@ fn test_fchown() { #[test] #[cfg(not(target_os = "redox"))] fn test_fchownat() { + use nix::fcntl::AtFlags; + let _dr = crate::DirRestore::new(); // Testing for anything other than our own UID/GID is hard. let uid = Some(getuid()); @@ -540,14 +566,13 @@ fn test_fchownat() { let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); - fchownat(Some(dirfd), "file", uid, gid, FchownatFlags::FollowSymlink) - .unwrap(); + fchownat(Some(dirfd), "file", uid, gid, AtFlags::empty()).unwrap(); chdir(tempdir.path()).unwrap(); - fchownat(None, "file", uid, gid, FchownatFlags::FollowSymlink).unwrap(); + fchownat(None, "file", uid, gid, AtFlags::empty()).unwrap(); fs::remove_file(&path).unwrap(); - fchownat(None, "file", uid, gid, FchownatFlags::FollowSymlink).unwrap_err(); + fchownat(None, "file", uid, gid, AtFlags::empty()).unwrap_err(); } #[test] @@ -564,7 +589,7 @@ fn test_lseek() { assert_eq!(b"f123456", &buf); } -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[test] fn test_lseek64() { const CONTENTS: &[u8] = b"abcdef123456"; @@ -579,7 +604,7 @@ fn test_lseek64() { } cfg_if! { - if #[cfg(any(target_os = "android", target_os = "linux"))] { + if #[cfg(linux_android)] { macro_rules! require_acct{ () => { require_capability!("test_acct", CAP_SYS_PACCT); @@ -631,11 +656,12 @@ fn test_acct() { acct::disable().unwrap(); } +#[cfg_attr(target_os = "hurd", ignore)] #[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); + // PATH_MAX is limited on most platforms, so it makes a good test + let path_max = fpathconf(f, PathconfVar::PATH_MAX); assert!( path_max .expect("fpathconf failed") @@ -644,9 +670,10 @@ fn test_fpathconf_limited() { ); } +#[cfg_attr(target_os = "hurd", ignore)] #[test] fn test_pathconf_limited() { - // AFAIK, PATH_MAX is limited on all platforms, so it makes a good test + // PATH_MAX is limited on most platforms, so it makes a good test let path_max = pathconf("/", PathconfVar::PATH_MAX); assert!( path_max @@ -656,9 +683,10 @@ fn test_pathconf_limited() { ); } +#[cfg_attr(target_os = "hurd", ignore)] #[test] fn test_sysconf_limited() { - // AFAIK, OPEN_MAX is limited on all platforms, so it makes a good test + // OPEN_MAX is limited on most platforms, so it makes a good test let open_max = sysconf(SysconfVar::OPEN_MAX); assert!( open_max @@ -678,13 +706,7 @@ fn test_sysconf_unsupported() { 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" -))] +#[cfg(any(linux_android, freebsdlike, target_os = "openbsd"))] #[test] fn test_getresuid() { let resuids = getresuid().unwrap(); @@ -693,13 +715,7 @@ fn test_getresuid() { 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" -))] +#[cfg(any(linux_android, freebsdlike, target_os = "openbsd"))] #[test] fn test_getresgid() { let resgids = getresgid().unwrap(); @@ -714,12 +730,12 @@ fn test_getresgid() { fn test_pipe() { let (fd0, fd1) = pipe().unwrap(); let m0 = stat::SFlag::from_bits_truncate( - stat::fstat(fd0).unwrap().st_mode as mode_t, + stat::fstat(fd0.as_raw_fd()).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, + stat::fstat(fd1.as_raw_fd()).unwrap().st_mode as mode_t, ); assert_eq!(m1, SFlag::S_IFIFO); } @@ -727,25 +743,25 @@ fn test_pipe() { // 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", + linux_android, + freebsdlike, + solarish, + netbsdlike, 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()); + let f0 = FdFlag::from_bits_truncate( + fcntl(fd0.as_raw_fd(), FcntlArg::F_GETFD).unwrap(), + ); assert!(f0.contains(FdFlag::FD_CLOEXEC)); - let f1 = FdFlag::from_bits_truncate(fcntl(fd1, FcntlArg::F_GETFD).unwrap()); + let f1 = FdFlag::from_bits_truncate( + fcntl(fd1.as_raw_fd(), FcntlArg::F_GETFD).unwrap(), + ); assert!(f1.contains(FdFlag::FD_CLOEXEC)); } @@ -881,6 +897,8 @@ fn test_symlinkat() { #[test] #[cfg(not(any(target_os = "redox", target_os = "haiku")))] fn test_linkat_file() { + use nix::fcntl::AtFlags; + let tempdir = tempdir().unwrap(); let oldfilename = "foo.txt"; let oldfilepath = tempdir.path().join(oldfilename); @@ -902,7 +920,7 @@ fn test_linkat_file() { oldfilename, Some(dirfd), newfilename, - LinkatFlags::SymlinkFollow, + AtFlags::AT_SYMLINK_FOLLOW, ) .unwrap(); assert!(newfilepath.exists()); @@ -911,6 +929,8 @@ fn test_linkat_file() { #[test] #[cfg(not(any(target_os = "redox", target_os = "haiku")))] fn test_linkat_olddirfd_none() { + use nix::fcntl::AtFlags; + let _dr = crate::DirRestore::new(); let tempdir_oldfile = tempdir().unwrap(); @@ -939,7 +959,7 @@ fn test_linkat_olddirfd_none() { oldfilename, Some(dirfd), newfilename, - LinkatFlags::SymlinkFollow, + AtFlags::AT_SYMLINK_FOLLOW, ) .unwrap(); assert!(newfilepath.exists()); @@ -948,6 +968,8 @@ fn test_linkat_olddirfd_none() { #[test] #[cfg(not(any(target_os = "redox", target_os = "haiku")))] fn test_linkat_newdirfd_none() { + use nix::fcntl::AtFlags; + let _dr = crate::DirRestore::new(); let tempdir_oldfile = tempdir().unwrap(); @@ -976,20 +998,17 @@ fn test_linkat_newdirfd_none() { oldfilename, None, newfilename, - LinkatFlags::SymlinkFollow, + AtFlags::AT_SYMLINK_FOLLOW, ) .unwrap(); assert!(newfilepath.exists()); } #[test] -#[cfg(not(any( - target_os = "ios", - target_os = "macos", - target_os = "redox", - target_os = "haiku" -)))] +#[cfg(not(any(apple_targets, target_os = "redox", target_os = "haiku")))] fn test_linkat_no_follow_symlink() { + use nix::fcntl::AtFlags; + let _m = crate::CWD_LOCK.read(); let tempdir = tempdir().unwrap(); @@ -1019,7 +1038,7 @@ fn test_linkat_no_follow_symlink() { symoldfilename, Some(dirfd), newfilename, - LinkatFlags::NoSymlinkFollow, + AtFlags::empty(), ) .unwrap(); @@ -1033,6 +1052,8 @@ fn test_linkat_no_follow_symlink() { #[test] #[cfg(not(any(target_os = "redox", target_os = "haiku")))] fn test_linkat_follow_symlink() { + use nix::fcntl::AtFlags; + let _m = crate::CWD_LOCK.read(); let tempdir = tempdir().unwrap(); @@ -1062,7 +1083,7 @@ fn test_linkat_follow_symlink() { symoldfilename, Some(dirfd), newfilename, - LinkatFlags::SymlinkFollow, + AtFlags::AT_SYMLINK_FOLLOW, ) .unwrap(); @@ -1070,8 +1091,8 @@ fn test_linkat_follow_symlink() { // Check the file type of the new link assert_eq!( - (stat::SFlag::from_bits_truncate(newfilestat.st_mode as mode_t) - & SFlag::S_IFMT), + stat::SFlag::from_bits_truncate(newfilestat.st_mode as mode_t) + & SFlag::S_IFMT, SFlag::S_IFREG ); @@ -1159,8 +1180,6 @@ fn test_access_file_exists() { .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() { @@ -1177,7 +1196,7 @@ fn test_user_into_passwd() { } /// Tests setting the filesystem UID with `setfsuid`. -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[test] fn test_setfsuid() { use std::os::unix::fs::PermissionsExt; @@ -1230,9 +1249,11 @@ fn test_ttyname() { 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()) + let fds = fs::OpenOptions::new() + .read(true) + .write(true) + .open(Path::new(&sname)) .expect("open failed"); - assert!(fds > 0); let name = ttyname(fds).expect("ttyname failed"); assert!(name.starts_with("/dev")); @@ -1242,35 +1263,17 @@ fn test_ttyname() { #[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)); + assert_eq!(ttyname(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", -))] +#[cfg(bsd)] 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_a, gid_a) = getpeereid(sock_a).unwrap(); + let (uid_b, gid_b) = getpeereid(sock_b).unwrap(); let uid = geteuid(); let gid = getegid(); @@ -1282,20 +1285,6 @@ fn test_getpeereid() { } #[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; @@ -1364,11 +1353,7 @@ fn test_faccessat_file_exists() { } #[test] -#[cfg(any( - all(target_os = "linux", not(target_env = "uclibc")), - target_os = "freebsd", - target_os = "dragonfly" -))] +#[cfg(any(all(target_os = "linux", not(target_env = "uclibc")), freebsdlike))] fn test_eaccess_not_existing() { let tempdir = tempdir().unwrap(); let dir = tempdir.path().join("does_not_exist.txt"); @@ -1379,11 +1364,7 @@ fn test_eaccess_not_existing() { } #[test] -#[cfg(any( - all(target_os = "linux", not(target_env = "uclibc")), - target_os = "freebsd", - target_os = "dragonfly" -))] +#[cfg(any(all(target_os = "linux", not(target_env = "uclibc")), freebsdlike))] fn test_eaccess_file_exists() { let tempdir = tempdir().unwrap(); let path = tempdir.path().join("does_exist.txt"); @@ -1391,3 +1372,14 @@ fn test_eaccess_file_exists() { eaccess(&path, AccessFlags::R_OK | AccessFlags::W_OK) .expect("assertion failed"); } + +#[test] +#[cfg(bsd)] +fn test_group_from() { + let group = Group::from_name("wheel").unwrap().unwrap(); + assert!(group.name == "wheel"); + let group_id = group.gid; + let group = Group::from_gid(group_id).unwrap().unwrap(); + assert_eq!(group.gid, group_id); + assert_eq!(group.name, "wheel"); +} |