├── .github ├── dependabot.yml └── workflows │ └── main.yml ├── .gitignore ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── clippy.toml └── src ├── hermit.rs ├── lib.rs ├── sys.rs ├── unix.rs ├── wasi.rs └── windows.rs /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "cargo" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | - package-ecosystem: "github-actions" 8 | directory: "/" 9 | schedule: 10 | interval: "weekly" 11 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - main 5 | pull_request: 6 | schedule: 7 | - cron: '5 21 * * 5' 8 | workflow_dispatch: 9 | 10 | name: CI 11 | 12 | jobs: 13 | test: 14 | name: Test 15 | runs-on: ${{ matrix.os }} 16 | strategy: 17 | matrix: 18 | os: [ubuntu-latest, macos-latest, windows-latest] 19 | rust: [stable, nightly, '1.56'] 20 | steps: 21 | - name: Checkout repository 22 | uses: actions/checkout@v4 23 | - name: Install toolchain 24 | uses: dtolnay/rust-toolchain@master 25 | with: 26 | toolchain: ${{ matrix.rust }} 27 | - name: Pin to old dependency versions (Rust 1.56 only) 28 | if: matrix.rust == '1.56' 29 | run: | 30 | cargo update -p libc --precise 0.2.163 31 | cargo update -p windows-sys --precise 0.52.0 32 | - name: Setup cache 33 | uses: Swatinem/rust-cache@v2 34 | - name: Test (no features) 35 | run: cargo test --no-default-features 36 | - name: Test (all features) 37 | run: cargo test --all-features 38 | 39 | 40 | wasi: 41 | name: Test WASI 42 | runs-on: ubuntu-latest 43 | steps: 44 | - name: Checkout repository 45 | uses: actions/checkout@v4 46 | - name: Install toolchain 47 | uses: dtolnay/rust-toolchain@nightly 48 | with: 49 | targets: wasm32-wasip2 50 | - name: Install wasmtime 51 | run: | 52 | curl https://wasmtime.dev/install.sh -sSf | bash 53 | echo "$HOME/.wasmtime/bin" >> $GITHUB_PATH 54 | - name: Test (no features) 55 | run: CARGO_TARGET_WASM32_WASIP2_RUNNER=wasmtime cargo test --target wasm32-wasip2 --no-default-features 56 | - name: Test (all features) 57 | run: CARGO_TARGET_WASM32_WASIP2_RUNNER=wasmtime cargo test --target wasm32-wasip2 --all-features 58 | 59 | emscripten: 60 | name: Test Emscripten 61 | runs-on: ubuntu-latest 62 | container: emscripten/emsdk:latest 63 | steps: 64 | - name: Checkout repository 65 | uses: actions/checkout@v4 66 | - name: Install toolchain 67 | uses: dtolnay/rust-toolchain@nightly 68 | with: 69 | targets: wasm32-unknown-emscripten 70 | - name: Test (no features) 71 | run: CARGO_TARGET_WASM32_UNKNOWN_EMSCRIPTEN_RUNNER=node cargo test --target wasm32-unknown-emscripten --no-default-features 72 | - name: Test (all features) 73 | run: CARGO_TARGET_WASM32_UNKNOWN_EMSCRIPTEN_RUNNER=node cargo test --target wasm32-unknown-emscripten --all-features 74 | 75 | 76 | lints: 77 | name: Rustfmt & Clippy 78 | runs-on: ubuntu-latest 79 | steps: 80 | - name: Checkout repository 81 | uses: actions/checkout@v4 82 | - name: Install toolchain 83 | uses: dtolnay/rust-toolchain@stable 84 | with: 85 | components: rustfmt, clippy 86 | - name: Check formatting 87 | run: cargo fmt --check 88 | - name: Check clippy 89 | run: cargo clippy -- -D warnings 90 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # [Unreleased] 2 | 3 | # [0.3.12] - 2025-05-12 4 | 5 | - Issue a better error message if the target is unsupported. 6 | [#110](https://github.com/lambda-fairy/rust-errno/pull/110) 7 | 8 | # [0.3.11] - 2025-04-04 9 | 10 | - Add VxWorks support 11 | [#105](https://github.com/lambda-fairy/rust-errno/pull/105) 12 | 13 | - Add cygwin support 14 | [#106](https://github.com/lambda-fairy/rust-errno/pull/106) 15 | 16 | # [0.3.10] - 2024-11-29 17 | 18 | - Update to windows-sys 0.59 19 | [#98](https://github.com/lambda-fairy/rust-errno/pull/98) 20 | 21 | - Support emscripten 22 | [#100](https://github.com/lambda-fairy/rust-errno/pull/100) 23 | 24 | - Remove Bitrig support 25 | [#99](https://github.com/lambda-fairy/rust-errno/pull/99) 26 | 27 | # [0.3.9] - 2024-05-07 28 | 29 | - Add visionOS support 30 | [#95](https://github.com/lambda-fairy/rust-errno/pull/95) 31 | 32 | # [0.3.8] - 2023-11-27 33 | 34 | - Update to windows-sys 0.52. 35 | [#91](https://github.com/lambda-fairy/rust-errno/pull/91) 36 | 37 | - Update minimum Rust version to 1.56 38 | [#91](https://github.com/lambda-fairy/rust-errno/pull/91) 39 | 40 | # [0.3.7] - 2023-11-15 41 | 42 | - Fix `to_string()` handling for unknown error codes 43 | [#88](https://github.com/lambda-fairy/rust-errno/pull/88) 44 | 45 | # [0.3.6] - 2023-11-07 46 | 47 | - Add support for tvOS and watchOS 48 | [#84](https://github.com/lambda-fairy/rust-errno/pull/84) 49 | 50 | - Added support for vita target 51 | [#86](https://github.com/lambda-fairy/rust-errno/pull/86) 52 | 53 | # [0.3.5] - 2023-10-08 54 | 55 | - Use __errno_location on DragonFly BSD 56 | [#82](https://github.com/lambda-fairy/rust-errno/pull/82) 57 | 58 | # [0.3.4] - 2023-10-01 59 | 60 | - Add GNU/Hurd support 61 | [#80](https://github.com/lambda-fairy/rust-errno/pull/80) 62 | 63 | # [0.3.3] - 2023-08-28 64 | 65 | - Disable "libc/std" in no-std configurations. 66 | [#77](https://github.com/lambda-fairy/rust-errno/pull/77) 67 | 68 | - Bump errno-dragonfly to 0.1.2 69 | [#75](https://github.com/lambda-fairy/rust-errno/pull/75) 70 | 71 | - Support for the ESP-IDF framework 72 | [#74](https://github.com/lambda-fairy/rust-errno/pull/74) 73 | 74 | # [0.3.2] - 2023-07-30 75 | 76 | - Fix build on Hermit 77 | [#73](https://github.com/lambda-fairy/rust-errno/pull/73) 78 | 79 | - Add support for QNX Neutrino 80 | [#72](https://github.com/lambda-fairy/rust-errno/pull/72) 81 | 82 | # [0.3.1] - 2023-04-08 83 | 84 | - Correct link name on redox 85 | [#69](https://github.com/lambda-fairy/rust-errno/pull/69) 86 | 87 | - Update windows-sys requirement from 0.45 to 0.48 88 | [#70](https://github.com/lambda-fairy/rust-errno/pull/70) 89 | 90 | # [0.3.0] - 2023-02-12 91 | 92 | - Add haiku support 93 | [#42](https://github.com/lambda-fairy/rust-errno/pull/42) 94 | 95 | - Add AIX support 96 | [#54](https://github.com/lambda-fairy/rust-errno/pull/54) 97 | 98 | - Add formatting with `#![no_std]` 99 | [#44](https://github.com/lambda-fairy/rust-errno/pull/44) 100 | 101 | - Switch from `winapi` to `windows-sys` [#55](https://github.com/lambda-fairy/rust-errno/pull/55) 102 | 103 | - Update minimum Rust version to 1.48 104 | [#48](https://github.com/lambda-fairy/rust-errno/pull/48) [#55](https://github.com/lambda-fairy/rust-errno/pull/55) 105 | 106 | - Upgrade to Rust 2018 edition [#59](https://github.com/lambda-fairy/rust-errno/pull/59) 107 | 108 | - wasm32-wasi: Use `__errno_location` instead of `feature(thread_local)`. [#66](https://github.com/lambda-fairy/rust-errno/pull/66) 109 | 110 | # [0.2.8] - 2021-10-27 111 | 112 | - Optionally support no_std 113 | [#31](https://github.com/lambda-fairy/rust-errno/pull/31) 114 | 115 | [Unreleased]: https://github.com/lambda-fairy/rust-errno/compare/v0.3.10...HEAD 116 | [0.3.10]: https://github.com/lambda-fairy/rust-errno/compare/v0.3.9...v0.3.10 117 | [0.3.9]: https://github.com/lambda-fairy/rust-errno/compare/v0.3.8...v0.3.9 118 | [0.3.8]: https://github.com/lambda-fairy/rust-errno/compare/v0.3.7...v0.3.8 119 | [0.3.7]: https://github.com/lambda-fairy/rust-errno/compare/v0.3.6...v0.3.7 120 | [0.3.6]: https://github.com/lambda-fairy/rust-errno/compare/v0.3.5...v0.3.6 121 | [0.3.5]: https://github.com/lambda-fairy/rust-errno/compare/v0.3.4...v0.3.5 122 | [0.3.4]: https://github.com/lambda-fairy/rust-errno/compare/v0.3.3...v0.3.4 123 | [0.3.3]: https://github.com/lambda-fairy/rust-errno/compare/v0.3.2...v0.3.3 124 | [0.3.2]: https://github.com/lambda-fairy/rust-errno/compare/v0.3.1...v0.3.2 125 | [0.3.1]: https://github.com/lambda-fairy/rust-errno/compare/v0.3.0...v0.3.1 126 | [0.3.0]: https://github.com/lambda-fairy/rust-errno/compare/v0.2.8...v0.3.0 127 | [0.2.8]: https://github.com/lambda-fairy/rust-errno/compare/v0.2.7...v0.2.8 128 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | name = "errno" 4 | version = "0.3.12" 5 | authors = ["Chris Wong ", "Dan Gohman "] 6 | 7 | license = "MIT OR Apache-2.0" 8 | edition = "2018" 9 | documentation = "https://docs.rs/errno" 10 | repository = "https://github.com/lambda-fairy/rust-errno" 11 | description = "Cross-platform interface to the `errno` variable." 12 | categories = ["no-std", "os"] 13 | rust-version = "1.56" 14 | 15 | [target.'cfg(unix)'.dependencies] 16 | libc = { version = "0.2", default-features = false } 17 | 18 | [target.'cfg(windows)'.dependencies.windows-sys] 19 | version = ">=0.52, <=0.59" 20 | features = [ 21 | "Win32_Foundation", 22 | "Win32_System_Diagnostics_Debug", 23 | ] 24 | 25 | [target.'cfg(target_os="wasi")'.dependencies] 26 | libc = { version = "0.2", default-features = false } 27 | 28 | [target.'cfg(target_os="hermit")'.dependencies] 29 | libc = { version = "0.2", default-features = false } 30 | 31 | [features] 32 | default = ["std"] 33 | std = ["libc/std"] 34 | 35 | # TODO: Remove this exemption when Cygwin support lands in Rust stable 36 | # https://github.com/rust-lang/rust/pull/134999 37 | [lints.rust.unexpected_cfgs] 38 | level = "warn" 39 | check-cfg = ['cfg(target_os, values("cygwin"))'] 40 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Chris Wong 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # errno [![CI](https://github.com/lambda-fairy/rust-errno/actions/workflows/main.yml/badge.svg)](https://github.com/lambda-fairy/rust-errno/actions/workflows/main.yml) [![Cargo](https://img.shields.io/crates/v/errno.svg)](https://crates.io/crates/errno) 2 | 3 | Cross-platform interface to the [`errno`][errno] variable. Works on Rust 1.56 or newer. 4 | 5 | Documentation is available at . 6 | 7 | [errno]: https://en.wikipedia.org/wiki/Errno.h 8 | 9 | 10 | ## Dependency 11 | 12 | Add to your `Cargo.toml`: 13 | 14 | ```toml 15 | [dependencies] 16 | errno = "*" 17 | ``` 18 | 19 | 20 | ## Comparison with `std::io::Error` 21 | 22 | The standard library provides [`Error::last_os_error`][last_os_error] which fetches `errno` in the same way. 23 | 24 | This crate provides these extra features: 25 | 26 | - No heap allocations 27 | - Optional `#![no_std]` support 28 | - A `set_errno` function 29 | 30 | [last_os_error]: https://doc.rust-lang.org/std/io/struct.Error.html#method.last_os_error 31 | 32 | 33 | ## Examples 34 | 35 | ```rust 36 | extern crate errno; 37 | use errno::{Errno, errno, set_errno}; 38 | 39 | // Get the current value of errno 40 | let e = errno(); 41 | 42 | // Set the current value of errno 43 | set_errno(e); 44 | 45 | // Extract the error code as an i32 46 | let code = e.0; 47 | 48 | // Display a human-friendly error message 49 | println!("Error {}: {}", code, e); 50 | ``` 51 | 52 | 53 | ## `#![no_std]` 54 | 55 | Enable `#![no_std]` support by disabling the default `std` feature: 56 | 57 | ```toml 58 | [dependencies] 59 | errno = { version = "*", default-features = false } 60 | ``` 61 | 62 | The `Error` impl will be unavailable. 63 | -------------------------------------------------------------------------------- /clippy.toml: -------------------------------------------------------------------------------- 1 | msrv = "1.56" 2 | -------------------------------------------------------------------------------- /src/hermit.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of `errno` functionality for RustyHermit. 2 | //! 3 | //! Currently, the error handling in RustyHermit isn't clearly 4 | //! defined. At the current stage of RustyHermit, only a placeholder 5 | //! is provided to be compatible to the classical errno interface. 6 | 7 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT 8 | // file at the top-level directory of this distribution and at 9 | // http://rust-lang.org/COPYRIGHT. 10 | // 11 | // Licensed under the Apache License, Version 2.0 or the MIT license 13 | // , at your 14 | // option. This file may not be copied, modified, or distributed 15 | // except according to those terms. 16 | 17 | use crate::Errno; 18 | 19 | pub fn with_description(_err: Errno, callback: F) -> T 20 | where 21 | F: FnOnce(Result<&str, Errno>) -> T, 22 | { 23 | callback(Ok("unknown error")) 24 | } 25 | 26 | pub const STRERROR_NAME: &str = "strerror_r"; 27 | 28 | pub fn errno() -> Errno { 29 | Errno(0) 30 | } 31 | 32 | pub fn set_errno(_: Errno) {} 33 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Cross-platform interface to the `errno` variable. 2 | //! 3 | //! # Examples 4 | //! ``` 5 | //! use errno::{Errno, errno, set_errno}; 6 | //! 7 | //! // Get the current value of errno 8 | //! let e = errno(); 9 | //! 10 | //! // Set the current value of errno 11 | //! set_errno(e); 12 | //! 13 | //! // Extract the error code as an i32 14 | //! let code = e.0; 15 | //! 16 | //! // Display a human-friendly error message 17 | //! println!("Error {}: {}", code, e); 18 | //! ``` 19 | 20 | #![cfg_attr(not(feature = "std"), no_std)] 21 | 22 | #[cfg_attr(unix, path = "unix.rs")] 23 | #[cfg_attr(windows, path = "windows.rs")] 24 | #[cfg_attr(target_os = "wasi", path = "wasi.rs")] 25 | #[cfg_attr(target_os = "hermit", path = "hermit.rs")] 26 | mod sys; 27 | 28 | use core::fmt; 29 | #[cfg(feature = "std")] 30 | use std::error::Error; 31 | #[cfg(feature = "std")] 32 | use std::io; 33 | 34 | /// Wraps a platform-specific error code. 35 | /// 36 | /// The `Display` instance maps the code to a human-readable string. It 37 | /// calls [`strerror_r`][1] under POSIX, and [`FormatMessageW`][2] on 38 | /// Windows. 39 | /// 40 | /// [1]: http://pubs.opengroup.org/onlinepubs/009695399/functions/strerror.html 41 | /// [2]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351%28v=vs.85%29.aspx 42 | #[derive(Copy, Clone, Eq, Ord, PartialEq, PartialOrd, Hash)] 43 | pub struct Errno(pub i32); 44 | 45 | impl fmt::Debug for Errno { 46 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 47 | sys::with_description(*self, |desc| { 48 | fmt.debug_struct("Errno") 49 | .field("code", &self.0) 50 | .field("description", &desc.ok()) 51 | .finish() 52 | }) 53 | } 54 | } 55 | 56 | impl fmt::Display for Errno { 57 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 58 | sys::with_description(*self, |desc| match desc { 59 | Ok(desc) => fmt.write_str(desc), 60 | Err(fm_err) => write!( 61 | fmt, 62 | "OS error {} ({} returned error {})", 63 | self.0, 64 | sys::STRERROR_NAME, 65 | fm_err.0 66 | ), 67 | }) 68 | } 69 | } 70 | 71 | impl From for i32 { 72 | fn from(e: Errno) -> Self { 73 | e.0 74 | } 75 | } 76 | 77 | #[cfg(feature = "std")] 78 | impl Error for Errno { 79 | // TODO: Remove when MSRV >= 1.27 80 | #[allow(deprecated)] 81 | fn description(&self) -> &str { 82 | "system error" 83 | } 84 | } 85 | 86 | #[cfg(feature = "std")] 87 | impl From for io::Error { 88 | fn from(errno: Errno) -> Self { 89 | io::Error::from_raw_os_error(errno.0) 90 | } 91 | } 92 | 93 | /// Returns the platform-specific value of `errno`. 94 | pub fn errno() -> Errno { 95 | sys::errno() 96 | } 97 | 98 | /// Sets the platform-specific value of `errno`. 99 | pub fn set_errno(err: Errno) { 100 | sys::set_errno(err) 101 | } 102 | 103 | #[test] 104 | fn it_works() { 105 | let x = errno(); 106 | set_errno(x); 107 | } 108 | 109 | #[cfg(feature = "std")] 110 | #[test] 111 | fn it_works_with_to_string() { 112 | let x = errno(); 113 | let _ = x.to_string(); 114 | } 115 | 116 | #[cfg(feature = "std")] 117 | #[test] 118 | fn check_description() { 119 | let expect = if cfg!(windows) { 120 | "Incorrect function." 121 | } else if cfg!(target_os = "illumos") { 122 | "Not owner" 123 | } else if cfg!(target_os = "wasi") || cfg!(target_os = "emscripten") { 124 | "Argument list too long" 125 | } else if cfg!(target_os = "haiku") { 126 | "Operation not allowed" 127 | } else if cfg!(target_os = "vxworks") { 128 | "operation not permitted" 129 | } else { 130 | "Operation not permitted" 131 | }; 132 | 133 | let errno_code = if cfg!(target_os = "haiku") { 134 | -2147483633 135 | } else if cfg!(target_os = "hurd") { 136 | 1073741825 137 | } else { 138 | 1 139 | }; 140 | set_errno(Errno(errno_code)); 141 | 142 | assert_eq!(errno().to_string(), expect); 143 | assert_eq!( 144 | format!("{:?}", errno()), 145 | format!( 146 | "Errno {{ code: {}, description: Some({:?}) }}", 147 | errno_code, expect 148 | ) 149 | ); 150 | } 151 | 152 | #[cfg(feature = "std")] 153 | #[test] 154 | fn check_error_into_errno() { 155 | const ERROR_CODE: i32 = 1; 156 | 157 | let error = io::Error::from_raw_os_error(ERROR_CODE); 158 | let new_error: io::Error = Errno(ERROR_CODE).into(); 159 | assert_eq!(error.kind(), new_error.kind()); 160 | } 161 | -------------------------------------------------------------------------------- /src/sys.rs: -------------------------------------------------------------------------------- 1 | //! A default sys.rs for unrecognized targets. 2 | //! 3 | //! If lib.rs doesn't recognize the target, it defaults to using this file, 4 | //! which issues an explanatory compile error. 5 | 6 | // If there is no OS, there's no `errno` or equivalent defined. 7 | #[cfg(any(target_os = "unknown", target_os = "none"))] 8 | compile_error!("The target OS is \"unknown\" or \"none\", so it's unsupported by the errno crate."); 9 | 10 | // If there is an OS, support may be added. 11 | #[cfg(not(any(target_os = "unknown", target_os = "none")))] 12 | compile_error!("The target OS is not yet supported in the errno crate."); 13 | 14 | // The following define the functions of the normal implementations 15 | // so that the user doesn't see uninteresting errors after the 16 | // errors above. 17 | 18 | use crate::Errno; 19 | 20 | pub fn with_description(_err: Errno, _callback: F) -> T 21 | where 22 | F: FnOnce(Result<&str, Errno>) -> T, 23 | { 24 | unreachable!() 25 | } 26 | 27 | pub const STRERROR_NAME: &str = ""; 28 | 29 | pub fn errno() -> Errno { 30 | unreachable!() 31 | } 32 | 33 | pub fn set_errno(_: Errno) { 34 | unreachable!() 35 | } 36 | -------------------------------------------------------------------------------- /src/unix.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of `errno` functionality for Unix systems. 2 | //! 3 | //! Adapted from `src/libstd/sys/unix/os.rs` in the Rust distribution. 4 | 5 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT 6 | // file at the top-level directory of this distribution and at 7 | // http://rust-lang.org/COPYRIGHT. 8 | // 9 | // Licensed under the Apache License, Version 2.0 or the MIT license 11 | // , at your 12 | // option. This file may not be copied, modified, or distributed 13 | // except according to those terms. 14 | 15 | use core::str; 16 | use libc::{self, c_int, size_t, strerror_r, strlen}; 17 | 18 | use crate::Errno; 19 | 20 | fn from_utf8_lossy(input: &[u8]) -> &str { 21 | match str::from_utf8(input) { 22 | Ok(valid) => valid, 23 | Err(error) => unsafe { str::from_utf8_unchecked(&input[..error.valid_up_to()]) }, 24 | } 25 | } 26 | 27 | pub fn with_description(err: Errno, callback: F) -> T 28 | where 29 | F: FnOnce(Result<&str, Errno>) -> T, 30 | { 31 | let mut buf = [0u8; 1024]; 32 | let c_str = unsafe { 33 | let rc = strerror_r(err.0, buf.as_mut_ptr() as *mut _, buf.len() as size_t); 34 | if rc != 0 { 35 | // Handle negative return codes for compatibility with glibc < 2.13 36 | let fm_err = match rc < 0 { 37 | true => errno(), 38 | false => Errno(rc), 39 | }; 40 | if fm_err != Errno(libc::ERANGE) { 41 | return callback(Err(fm_err)); 42 | } 43 | } 44 | let c_str_len = strlen(buf.as_ptr() as *const _); 45 | &buf[..c_str_len] 46 | }; 47 | callback(Ok(from_utf8_lossy(c_str))) 48 | } 49 | 50 | pub const STRERROR_NAME: &str = "strerror_r"; 51 | 52 | pub fn errno() -> Errno { 53 | unsafe { Errno(*errno_location()) } 54 | } 55 | 56 | pub fn set_errno(Errno(errno): Errno) { 57 | unsafe { 58 | *errno_location() = errno; 59 | } 60 | } 61 | 62 | extern "C" { 63 | #[cfg_attr( 64 | any( 65 | target_os = "macos", 66 | target_os = "ios", 67 | target_os = "tvos", 68 | target_os = "watchos", 69 | target_os = "visionos", 70 | target_os = "freebsd" 71 | ), 72 | link_name = "__error" 73 | )] 74 | #[cfg_attr( 75 | any( 76 | target_os = "openbsd", 77 | target_os = "netbsd", 78 | target_os = "android", 79 | target_os = "espidf", 80 | target_os = "vxworks", 81 | target_os = "cygwin", 82 | target_env = "newlib" 83 | ), 84 | link_name = "__errno" 85 | )] 86 | #[cfg_attr( 87 | any(target_os = "solaris", target_os = "illumos"), 88 | link_name = "___errno" 89 | )] 90 | #[cfg_attr(target_os = "haiku", link_name = "_errnop")] 91 | #[cfg_attr( 92 | any( 93 | target_os = "linux", 94 | target_os = "hurd", 95 | target_os = "redox", 96 | target_os = "dragonfly", 97 | target_os = "emscripten", 98 | ), 99 | link_name = "__errno_location" 100 | )] 101 | #[cfg_attr(target_os = "aix", link_name = "_Errno")] 102 | #[cfg_attr(target_os = "nto", link_name = "__get_errno_ptr")] 103 | fn errno_location() -> *mut c_int; 104 | } 105 | -------------------------------------------------------------------------------- /src/wasi.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of `errno` functionality for WASI. 2 | //! 3 | //! Adapted from `unix.rs`. 4 | 5 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT 6 | // file at the top-level directory of this distribution and at 7 | // http://rust-lang.org/COPYRIGHT. 8 | // 9 | // Licensed under the Apache License, Version 2.0 or the MIT license 11 | // , at your 12 | // option. This file may not be copied, modified, or distributed 13 | // except according to those terms. 14 | 15 | use core::str; 16 | use libc::{self, c_int, size_t, strerror_r, strlen}; 17 | 18 | use crate::Errno; 19 | 20 | fn from_utf8_lossy(input: &[u8]) -> &str { 21 | match str::from_utf8(input) { 22 | Ok(valid) => valid, 23 | Err(error) => unsafe { str::from_utf8_unchecked(&input[..error.valid_up_to()]) }, 24 | } 25 | } 26 | 27 | pub fn with_description(err: Errno, callback: F) -> T 28 | where 29 | F: FnOnce(Result<&str, Errno>) -> T, 30 | { 31 | let mut buf = [0u8; 1024]; 32 | let c_str = unsafe { 33 | let rc = strerror_r(err.0, buf.as_mut_ptr() as *mut _, buf.len() as size_t); 34 | if rc != 0 { 35 | let fm_err = Errno(rc); 36 | if fm_err != Errno(libc::ERANGE) { 37 | return callback(Err(fm_err)); 38 | } 39 | } 40 | let c_str_len = strlen(buf.as_ptr() as *const _); 41 | &buf[..c_str_len] 42 | }; 43 | callback(Ok(from_utf8_lossy(c_str))) 44 | } 45 | 46 | pub const STRERROR_NAME: &str = "strerror_r"; 47 | 48 | pub fn errno() -> Errno { 49 | unsafe { Errno(*__errno_location()) } 50 | } 51 | 52 | pub fn set_errno(Errno(new_errno): Errno) { 53 | unsafe { 54 | *__errno_location() = new_errno; 55 | } 56 | } 57 | 58 | extern "C" { 59 | fn __errno_location() -> *mut c_int; 60 | } 61 | -------------------------------------------------------------------------------- /src/windows.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of `errno` functionality for Windows. 2 | //! 3 | //! Adapted from `src/libstd/sys/windows/os.rs` in the Rust distribution. 4 | 5 | // Copyright 2014 The Rust Project Developers. See the COPYRIGHT 6 | // file at the top-level directory of this distribution and at 7 | // http://rust-lang.org/COPYRIGHT. 8 | // 9 | // Licensed under the Apache License, Version 2.0 or the MIT license 11 | // , at your 12 | // option. This file may not be copied, modified, or distributed 13 | // except according to those terms. 14 | 15 | use core::char::{self, REPLACEMENT_CHARACTER}; 16 | use core::ptr; 17 | use core::str; 18 | use windows_sys::Win32::Foundation::{GetLastError, SetLastError, WIN32_ERROR}; 19 | use windows_sys::Win32::System::Diagnostics::Debug::{ 20 | FormatMessageW, FORMAT_MESSAGE_FROM_SYSTEM, FORMAT_MESSAGE_IGNORE_INSERTS, 21 | }; 22 | 23 | use crate::Errno; 24 | 25 | fn from_utf16_lossy<'a>(input: &[u16], output: &'a mut [u8]) -> &'a str { 26 | let mut output_len = 0; 27 | for c in char::decode_utf16(input.iter().copied().take_while(|&x| x != 0)) 28 | .map(|x| x.unwrap_or(REPLACEMENT_CHARACTER)) 29 | { 30 | let c_len = c.len_utf8(); 31 | if c_len > output.len() - output_len { 32 | break; 33 | } 34 | c.encode_utf8(&mut output[output_len..]); 35 | output_len += c_len; 36 | } 37 | unsafe { str::from_utf8_unchecked(&output[..output_len]) } 38 | } 39 | 40 | pub fn with_description(err: Errno, callback: F) -> T 41 | where 42 | F: FnOnce(Result<&str, Errno>) -> T, 43 | { 44 | // This value is calculated from the macro 45 | // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT) 46 | let lang_id = 0x0800_u32; 47 | 48 | let mut buf = [0u16; 2048]; 49 | 50 | unsafe { 51 | let res = FormatMessageW( 52 | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 53 | ptr::null_mut(), 54 | err.0 as u32, 55 | lang_id, 56 | buf.as_mut_ptr(), 57 | buf.len() as u32, 58 | ptr::null_mut(), 59 | ); 60 | if res == 0 { 61 | // Sometimes FormatMessageW can fail e.g. system doesn't like lang_id 62 | let fm_err = errno(); 63 | return callback(Err(fm_err)); 64 | } 65 | 66 | let mut msg = [0u8; 2048]; 67 | let msg = from_utf16_lossy(&buf[..res as usize], &mut msg[..]); 68 | // Trim trailing CRLF inserted by FormatMessageW 69 | callback(Ok(msg.trim_end())) 70 | } 71 | } 72 | 73 | pub const STRERROR_NAME: &str = "FormatMessageW"; 74 | 75 | pub fn errno() -> Errno { 76 | unsafe { Errno(GetLastError() as i32) } 77 | } 78 | 79 | pub fn set_errno(Errno(errno): Errno) { 80 | unsafe { SetLastError(errno as WIN32_ERROR) } 81 | } 82 | --------------------------------------------------------------------------------