// SPDX-License-Identifier: MPL-2.0 OR LGPL-3.0-or-later /* * libpathrs: safe path resolution on Linux * Copyright (C) 2019-2025 SUSE LLC * Copyright (C) 2026 Aleksa Sarai * * == MPL-2.0 == * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. * * Alternatively, this Source Code Form may also (at your option) be used * under the terms of the GNU Lesser General Public License Version 3, as * described below: * * == LGPL-3.0-or-later == * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifdef __CBINDGEN_ALIGNED #undef __CBINDGEN_ALIGNED #endif #define __CBINDGEN_ALIGNED(n) __attribute__((aligned(n))) #ifndef LIBPATHRS_H #define LIBPATHRS_H /* * WARNING: This file was auto-generated by rust-cbindgen. Don't modify it. * Instead, re-generate it with: * % cbindgen -c cbindgen.toml -o include/pathrs.h */ #include #include #include #include #include #include /* * Returns whether the given numerical value is a libpathrs error (which can be * passed to pathrs_errorinfo()). Users are recommended to use this instead of * a bare `<0` comparison because some functions may return a negative number * even in a success condition. */ #define IS_PATHRS_ERR(ret) ((ret) < __PATHRS_MAX_ERR_VALUE) /* * Used to construct pathrs_proc_base_t values for a PID (or TID). Passing * PATHRS_PROC_PID(pid) to pathrs_proc_*() as pathrs_proc_base_t will cause * libpathrs to use /proc/$pid as the base of the operation. * * This is essentially functionally equivalent to prefixing "$pid/" to the * subpath argument and using PATHRS_PROC_ROOT. * * Note that this operation is inherently racy -- the process referenced by this * PID may have died and the PID recycled with a different process. In * principle, this means that it is only really safe to use this with: * * - PID 1 (the init process), as that PID cannot ever get recycled. * - Your current PID (though you should just use PATHRS_PROC_SELF). * - Your current TID (though you should just use PATHRS_PROC_THREAD_SELF), * or _possibly_ other TIDs in your thread-group if you are absolutely sure * they have not been reaped (typically with pthread_join(3), though there * are other ways). * - PIDs of child processes (as long as you are sure that no other part of * your program incorrectly catches or ignores SIGCHLD, and that you do it * *before* you call wait(2) or any equivalent method that could reap * zombies). * * Outside of those specific uses, users should probably avoid using this. */ #define PATHRS_PROC_PID(n) (__PATHRS_PROC_TYPE_PID | (n)) /* * A sentinel value to tell `pathrs_proc_*` methods to use the default procfs * root handle (which may be globally cached). */ #define PATHRS_PROC_DEFAULT_ROOTFD -9 /* (-EBADF) */ /** * Bits in `pathrs_proc_base_t` that indicate the type of the base value. * * NOTE: This is used internally by libpathrs. You should avoid using this * macro if possible. */ #define __PATHRS_PROC_TYPE_MASK 18446744069414584320ull /** * Bits in `pathrs_proc_base_t` that must be set for `/proc/$pid` values. Don't * use this directly, instead use `PATHRS_PROC_PID(n)` to convert a PID to an * appropriate `pathrs_proc_base_t` value. * * NOTE: This is used internally by libpathrs. You should avoid using this * macro if possible. */ #define __PATHRS_PROC_TYPE_PID 9223372036854775808ull /** * Construct a completely unmasked procfs handle. * * This is equivalent to [`ProcfsHandleBuilder::unmasked`], and is meant as * a flag argument to [`ProcfsOpenFlags`] (the `flags` field in `struct * pathrs_procfs_open_how`) for use with pathrs_procfs_open(). */ #define PATHRS_PROCFS_NEW_UNMASKED 1 /** * Indicate what base directory should be used when doing operations with * `pathrs_proc_*`. In addition to the values defined here, the following * macros can be used for other values: * * * `PATHRS_PROC_PID(pid)` refers to the `/proc/` directory for the * process with PID (or TID) `pid`. * * Note that this operation is inherently racy and should probably avoided * for most uses -- see the block comment above `PATHRS_PROC_PID(n)` for * more details. * * Unknown values will result in an error being returned. */ enum pathrs_proc_base_t { /** * Use /proc. Note that this mode may be more expensive because we have * to take steps to try to avoid leaking unmasked procfs handles, so you * should use PATHRS_PROC_SELF if you can. */ PATHRS_PROC_ROOT = 18446744067006164835ull, /** * Use /proc/self. For most programs, this is the standard choice. */ PATHRS_PROC_SELF = 18446744065272536607ull, /** * Use /proc/thread-self. In multi-threaded programs where one thread has a * different CLONE_FS, it is possible for /proc/self to point the wrong * thread and so /proc/thread-self may be necessary. * * NOTE: Using /proc/thread-self may require care if used from languages * where your code can change threads without warning and old threads can * be killed (such as Go -- where you want to use runtime.LockOSThread). */ PATHRS_PROC_THREAD_SELF = 18446744066171166239ull, }; typedef uint64_t pathrs_proc_base_t; typedef struct { uint64_t flags; } pathrs_procfs_open_how; /** * Attempts to represent a Rust Error type in C. This structure must be freed * using pathrs_errorinfo_free(). */ typedef struct __CBINDGEN_ALIGNED(8) { /** * Raw errno(3) value of the underlying error (or 0 if the source of the * error was not due to a syscall error). */ uint64_t saved_errno; /** * Textual description of the error. */ const char *description; } pathrs_error_t; /** * Represents the version information of the runtime libpathrs library. */ typedef struct { /** * Pointer to static version string containing the crate version. */ const char * version_string; } pathrs_version_info_t; /** * The smallest return value which cannot be a libpathrs error ID. * * While all libpathrs error IDs are negative numbers, some functions may * return a negative number in a success scenario. This macro defines the high * range end of the numbers that can be used as an error ID. Don't use this * value directly, instead use `IS_PATHRS_ERR(ret)` to check if a returned * value is an error or not. * * NOTE: This is used internally by libpathrs. You should avoid using this * macro if possible. */ #define __PATHRS_MAX_ERR_VALUE -4096 /** * Open a root handle. * * The provided path must be an existing directory. * * Note that root handles are not special -- this function is effectively * equivalent to * * ```c * fd = open(path, O_PATH|O_DIRECTORY); * ``` * * # Return Value * * On success, this function returns a file descriptor that can be used as a * root handle in subsequent pathrs_inroot_* operations. The file descriptor * will have the `O_CLOEXEC` flag automatically applied. * * If an error occurs, this function will return a negative error code. To * retrieve information about the error (such as a string describing the error, * the system errno(7) value associated with the error, etc), use * pathrs_errorinfo(). */ int pathrs_open_root(const char *path); /** * "Upgrade" an O_PATH file descriptor to a usable fd, suitable for reading and * writing. This does not consume the original file descriptor. (This can be * used with non-O_PATH file descriptors as well.) * * It should be noted that the use of O_CREAT *is not* supported (and will * result in an error). Handles only refer to *existing* files. Instead you * need to use pathrs_inroot_creat(). * * In addition, O_NOCTTY is automatically set when opening the path. If you * want to use the path as a controlling terminal, you will have to do * ioctl(fd, TIOCSCTTY, 0) yourself. * * # Return Value * * On success, this function returns a file descriptor. The file descriptor * will have the `O_CLOEXEC` flag automatically applied. * * If an error occurs, this function will return a negative error code. To * retrieve information about the error (such as a string describing the error, * the system errno(7) value associated with the error, etc), use * pathrs_errorinfo(). */ int pathrs_reopen(int fd, uint64_t flags); /** * Resolve the given path within the rootfs referenced by root_fd. The path * *must already exist*, otherwise an error will occur. * * All symlinks (including trailing symlinks) are followed, but they are * resolved within the rootfs. If you wish to open a handle to the symlink * itself, use pathrs_inroot_resolve_nofollow(). * * # Return Value * * On success, this function returns an O_PATH file descriptor referencing the * resolved path. * * If an error occurs, this function will return a negative error code. To * retrieve information about the error (such as a string describing the error, * the system errno(7) value associated with the error, etc), use * pathrs_errorinfo(). */ int pathrs_inroot_resolve(int root_fd, const char *path); /** * pathrs_inroot_resolve_nofollow() is effectively an O_NOFOLLOW version of * pathrs_inroot_resolve(). Their behaviour is identical, except that * *trailing* symlinks will not be followed. If the final component is a * trailing symlink, an O_PATH|O_NOFOLLOW handle to the symlink itself is * returned. * * # Return Value * * On success, this function returns an O_PATH file descriptor referencing the * resolved path. * * If an error occurs, this function will return a negative error code. To * retrieve information about the error (such as a string describing the error, * the system errno(7) value associated with the error, etc), use * pathrs_errorinfo(). */ int pathrs_inroot_resolve_nofollow(int root_fd, const char *path); /** * pathrs_inroot_open() is effectively shorthand for pathrs_inroot_resolve() * followed by pathrs_reopen(). If you only need to open a path and don't care * about re-opening it later, this can be slightly more efficient than the * alternative for the openat2-based resolver as it doesn't require allocating * an extra file descriptor. For languages where C FFI is expensive (such as * Go), using this also saves a function call. * * If flags contains O_NOFOLLOW, the behaviour is like that of * pathrs_inroot_resolve_nofollow() followed by pathrs_reopen(). * * In addition, O_NOCTTY is automatically set when opening the path. If you * want to use the path as a controlling terminal, you will have to do * ioctl(fd, TIOCSCTTY, 0) yourself. * * # Return Value * * On success, this function returns a file descriptor. The file descriptor * will have the `O_CLOEXEC` flag automatically applied. * * If an error occurs, this function will return a negative error code. To * retrieve information about the error (such as a string describing the error, * the system errno(7) value associated with the error, etc), use * pathrs_errorinfo(). */ int pathrs_inroot_open(int root_fd, const char *path, uint64_t flags); /** * Get the target of a symlink within the rootfs referenced by root_fd. * * NOTE: The returned path is not modified to be "safe" outside of the * root. You should not use this path for doing further path lookups -- use * pathrs_inroot_resolve() instead. * * This method is just shorthand for: * * ```c * int linkfd = pathrs_inroot_resolve_nofollow(rootfd, path); * if (IS_PATHRS_ERR(linkfd)) { * liberr = fd; // for use with pathrs_errorinfo() * goto err; * } * copied = readlinkat(linkfd, "", linkbuf, linkbuf_size); * close(linkfd); * ``` * * # Return Value * * On success, this function copies the symlink contents to `linkbuf` (up to * `linkbuf_size` bytes) and returns the full size of the symlink path buffer. * This function will not copy the trailing NUL byte, and the return size does * not include the NUL byte. A `NULL` `linkbuf` or invalid `linkbuf_size` are * treated as zero-size buffers. * * NOTE: Unlike readlinkat(2), in the case where linkbuf is too small to * contain the symlink contents, pathrs_inroot_readlink() will return *the * number of bytes it would have copied if the buffer was large enough*. This * matches the behaviour of pathrs_proc_readlink(). * * If an error occurs, this function will return a negative error code. To * retrieve information about the error (such as a string describing the error, * the system errno(7) value associated with the error, etc), use * pathrs_errorinfo(). */ int pathrs_inroot_readlink(int root_fd, const char *path, char *linkbuf, size_t linkbuf_size); /** * Rename a path within the rootfs referenced by root_fd. The flags argument is * identical to the renameat2(2) flags that are supported on the system. * * # Future-proofing * * This function takes two `root_fd` arguments in order for future extensions * to be able to use them, but callers must specify the same *value* for both * arguments. (NOTE: This is not referring to the same underlying file, the * actual file descriptor number must be identical.) * * # Return Value * * On success, this function returns 0. * * If an error occurs, this function will return a negative error code. To * retrieve information about the error (such as a string describing the error, * the system errno(7) value associated with the error, etc), use * pathrs_errorinfo(). */ int pathrs_inroot_rename(int old_root_fd, const char *old_path, int new_root_fd, const char *new_path, uint64_t flags); /** * Remove the empty directory at path within the rootfs referenced by root_fd. * * The semantics are effectively equivalent to unlinkat(..., AT_REMOVEDIR). * This function will return an error if the path doesn't exist, was not a * directory, or was a non-empty directory. * * # Return Value * * On success, this function returns 0. * * If an error occurs, this function will return a negative error code. To * retrieve information about the error (such as a string describing the error, * the system errno(7) value associated with the error, etc), use * pathrs_errorinfo(). */ int pathrs_inroot_rmdir(int root_fd, const char *path); /** * Remove the file (a non-directory inode) at path within the rootfs referenced * by root_fd. * * The semantics are effectively equivalent to unlinkat(..., 0). This function * will return an error if the path doesn't exist or was a directory. * * # Return Value * * On success, this function returns 0. * * If an error occurs, this function will return a negative error code. To * retrieve information about the error (such as a string describing the error, * the system errno(7) value associated with the error, etc), use * pathrs_errorinfo(). */ int pathrs_inroot_unlink(int root_fd, const char *path); /** * Recursively delete the path and any children it contains if it is a * directory. The semantics are equivalent to `rm -r`. * * # Return Value * * On success, this function returns 0. * * If an error occurs, this function will return a negative error code. To * retrieve information about the error (such as a string describing the error, * the system errno(7) value associated with the error, etc), use * pathrs_errorinfo(). */ int pathrs_inroot_remove_all(int root_fd, const char *path); /** * Create a new regular file within the rootfs referenced by root_fd. This is * effectively an O_CREAT operation, and so (unlike pathrs_inroot_resolve()), * this function can be used on non-existent paths. * * If you want to ensure the creation is a new file, use O_EXCL. * * If you want to create a file without opening a handle to it, you can do * pathrs_inroot_mknod(root_fd, path, S_IFREG|mode, 0) instead. * * As with pathrs_reopen(), O_NOCTTY is automatically set when opening the * path. If you want to use the path as a controlling terminal, you will have * to do ioctl(fd, TIOCSCTTY, 0) yourself. * * NOTE: Unlike O_CREAT, pathrs_inroot_creat() will return an error if the * final component is a dangling symlink. O_CREAT will create such files, and * while openat2 does support this it would be difficult to implement this in * the emulated resolver. * * # Return Value * * On success, this function returns a file descriptor to the requested file. * The open flags are based on the provided flags. The file descriptor will * have the `O_CLOEXEC` flag automatically applied. * * If an error occurs, this function will return a negative error code. To * retrieve information about the error (such as a string describing the error, * the system errno(7) value associated with the error, etc), use * pathrs_errorinfo(). */ int pathrs_inroot_creat(int root_fd, const char *path, uint64_t flags, unsigned int mode); /** * Create a new directory within the rootfs referenced by root_fd. * * This is shorthand for pathrs_inroot_mknod(root_fd, path, S_IFDIR|mode, 0). * * # Return Value * * On success, this function returns 0. * * If an error occurs, this function will return a negative error code. To * retrieve information about the error (such as a string describing the error, * the system errno(7) value associated with the error, etc), use * pathrs_errorinfo(). */ int pathrs_inroot_mkdir(int root_fd, const char *path, unsigned int mode); /** * Create a new directory (and any of its path components if they don't exist) * within the rootfs referenced by root_fd. * * # Return Value * * On success, this function returns an O_DIRECTORY file descriptor to the * newly created directory. * * If an error occurs, this function will return a negative error code. To * retrieve information about the error (such as a string describing the error, * the system errno(7) value associated with the error, etc), use * pathrs_errorinfo(). */ int pathrs_inroot_mkdir_all(int root_fd, const char *path, unsigned int mode); /** * Create a inode within the rootfs referenced by root_fd. The type of inode to * be created is configured using the S_IFMT bits in mode (a-la mknod(2)). * * # Return Value * * On success, this function returns 0. * * If an error occurs, this function will return a negative error code. To * retrieve information about the error (such as a string describing the error, * the system errno(7) value associated with the error, etc), use * pathrs_errorinfo(). */ int pathrs_inroot_mknod(int root_fd, const char *path, unsigned int mode, dev_t dev); /** * Create a symlink within the rootfs referenced by root_fd. Note that the * symlink target string is not modified when creating the symlink. * * # Return Value * * On success, this function returns 0. * * If an error occurs, this function will return a negative error code. To * retrieve information about the error (such as a string describing the error, * the system errno(7) value associated with the error, etc), use * pathrs_errorinfo(). */ int pathrs_inroot_symlink(const char *target, int root_fd, const char *linkpath); /** * Create a hardlink within the rootfs referenced by root_fd. Both the hardlink * path and target are resolved within the rootfs. * * # Future-proofing * * This function takes two `root_fd` arguments in order for future extensions * to be able to use them, but callers must specify the same *value* for both * arguments. (NOTE: This is not referring to the same underlying file, the * actual file descriptor number must be identical.) * * The `flags` argument is included for future extensions and must be 0. * * # Return Value * * On success, this function returns 0. * * If an error occurs, this function will return a negative error code. To * retrieve information about the error (such as a string describing the error, * the system errno(7) value associated with the error, etc), use * pathrs_errorinfo(). */ int pathrs_inroot_hardlink(int old_root_fd, const char *old_path, int new_root_fd, const char *new_path, uint64_t flags); /** * Create a new (custom) procfs root handle. * * This is effectively a C wrapper around [`ProcfsHandleBuilder`], allowing you * to create a custom procfs root handle that can be used with other * `pathrs_proc_*at` methods. * * While most users should just use `PATHRS_PROC_DEFAULT_ROOTFD` (or the * non-`at` variants of `pathrs_proc_*`), creating an unmasked procfs root * handle (using `PATHRS_PROCFS_NEW_UNMASKED`) can be useful for programs that * need to operate on a lot of global procfs files. (Note that accessing global * procfs files does not *require* creating a custom procfs handle -- * `pathrs_proc_*` will automatically create a global-friendly handle * internally when necessary but will close it immediately after operating on * it.) * * # Extensible Structs * * The [`ProcfsOpenHow`] (`struct pathrs_procfs_open_how`) argument is * designed to be extensible, modelled after the extensible structs scheme used * by Linux (for syscalls such as [clone3(2)], [openat2(2)] and other such * syscalls). Normally one would use symbol versioning to achieve this, but * unfortunately Rust's symbol versioning support is incredibly primitive (one * might even say "non-existent") and so this system is more robust, even if * the calling convention is a little strange for userspace libraries. * * In addition to a pointer argument, the caller must also provide the size of * the structure it is passing. By providing this information, it is possible * for `pathrs_procfs_open()` to provide both forwards- and * backwards-compatibility, with size acting as an implicit version number. * (Because new extension fields will always be appended, the structure size * will always increase.) * * If we let `usize` be the structure specified by the caller, and `lsize` be * the size of the structure internal to libpathrs, then there are three cases * to consider: * * * If `usize == lsize`, then there is no version mismatch and the structure * provided by the caller can be used verbatim. * * If `usize < lsize`, then there are some extension fields which libpathrs * supports that the caller does not. Because a zero value in any added * extension field signifies a no-op, libpathrs treats all of the extension * fields not provided by the caller as having zero values. This provides * backwards-compatibility. * * If `usize > lsize`, then there are some extension fields which the caller * is aware of but this version of libpathrs does not support. Because any * extension field must have its zero values signify a no-op, libpathrs can * safely ignore the unsupported extension fields if they are all-zero. If * any unsupported extension fields are nonzero, then an `E2BIG` error is * returned. This provides forwards-compatibility. * * Because the definition of `struct pathrs_procfs_open_how` may open in the * future * * Because the definition of `struct pathrs_procfs_open_how` may change in the * future (with new fields being added when headers are updated), callers * should zero-fill the structure to ensure that recompiling the program with * new headers will not result in spurious errors at run time. The simplest * way is to use a designated initialiser: * * ```c * struct pathrs_procfs_open_how how = { * .flags = PATHRS_PROCFS_NEW_UNMASKED, * }; * ``` * * or explicitly using `memset(3)` or similar: * * ```c * struct pathrs_procfs_open_how how; * memset(&how, 0, sizeof(how)); * how.flags = PATHRS_PROCFS_NEW_UNMASKED; * ``` * * # Return Value * * On success, this function returns *either* a file descriptor *or* * `PATHRS_PROC_DEFAULT_ROOTFD` (this is a negative number, equal to `-EBADF`). * The file descriptor will have the `O_CLOEXEC` flag automatically applied. * * If an error occurs, this function will return a negative error code. To * retrieve information about the error (such as a string describing the error, * the system errno(7) value associated with the error, etc), use * pathrs_errorinfo(). * * [clone3(2)]: https://www.man7.org/linux/man-pages/man2/clone3.2.html * [openat2(2)]: https://www.man7.org/linux/man-pages/man2/openat2.2.html */ int pathrs_procfs_open(const pathrs_procfs_open_how *args, size_t size); /** * `pathrs_proc_open` but with a caller-provided file descriptor for `/proc`. * * Internally, `pathrs_proc_open` will attempt to use a cached copy of a very * restricted `/proc` handle (a detached mount object with `subset=pid` and * `hidepid=4`). If a user requests a global `/proc` file, a temporary handle * capable of accessing global files is created and destroyed after the * operation completes. * * For most users, this is more than sufficient. However, if a user needs to * operate on many global `/proc` files, the cost of creating handles can get * quite expensive. `pathrs_proc_openat` allows a user to manually manage the * global-friendly `/proc` handle. Note that passing a `subset=pid` file * descriptor to `pathrs_proc_openat` will *not* stop the automatic creation of * a global-friendly handle internally if necessary. * * In order to get the behaviour of `pathrs_proc_open`, you can pass the * special value `PATHRS_PROC_DEFAULT_ROOTFD` (`-EBADF`) as the `proc_rootfd` * argument. * * # Return Value * * On success, this function returns a file descriptor. The file descriptor * will have the `O_CLOEXEC` flag automatically applied. * * If an error occurs, this function will return a negative error code. To * retrieve information about the error (such as a string describing the error, * the system errno(7) value associated with the error, etc), use * pathrs_errorinfo(). */ int pathrs_proc_openat(int proc_rootfd, pathrs_proc_base_t base, const char *path, uint64_t flags); /** * Safely open a path inside a `/proc` handle. * * Any bind-mounts or other over-mounts will (depending on what kernel features * are available) be detected and an error will be returned. Non-trailing * symlinks are followed but care is taken to ensure the symlinks are * legitimate. * * Unless you intend to open a magic-link, `O_NOFOLLOW` should be set in flags. * Lookups with `O_NOFOLLOW` are guaranteed to never be tricked by bind-mounts * (on new enough Linux kernels). * * If you wish to resolve a magic-link, you need to unset `O_NOFOLLOW`. * Unfortunately (if libpathrs is using the regular host `/proc` mount), this * lookup mode cannot protect you against an attacker that can modify the mount * table during this operation. * * NOTE: Instead of using paths like `/proc/thread-self/fd`, `base` is used to * indicate what "base path" inside procfs is used. For example, to re-open a * file descriptor: * * ```c * fd = pathrs_proc_open(PATHRS_PROC_THREAD_SELF, "fd/101", O_RDWR); * if (IS_PATHRS_ERR(fd)) { * liberr = fd; // for use with pathrs_errorinfo() * goto err; * } * ``` * * # Return Value * * On success, this function returns a file descriptor. The file descriptor * will have the `O_CLOEXEC` flag automatically applied. * * If an error occurs, this function will return a negative error code. To * retrieve information about the error (such as a string describing the error, * the system errno(7) value associated with the error, etc), use * pathrs_errorinfo(). */ int pathrs_proc_open(pathrs_proc_base_t base, const char *path, uint64_t flags); /** * `pathrs_proc_readlink` but with a caller-provided file descriptor for * `/proc`. * * See the documentation of pathrs_proc_openat() for when this API might be * useful. * * # Return Value * * On success, this function copies the symlink contents to `linkbuf` (up to * `linkbuf_size` bytes) and returns the full size of the symlink path buffer. * This function will not copy the trailing NUL byte, and the return size does * not include the NUL byte. A `NULL` `linkbuf` or invalid `linkbuf_size` are * treated as zero-size buffers. * * NOTE: Unlike readlinkat(2), in the case where linkbuf is too small to * contain the symlink contents, pathrs_proc_readlink() will return *the number * of bytes it would have copied if the buffer was large enough*. This matches * the behaviour of pathrs_inroot_readlink(). * * If an error occurs, this function will return a negative error code. To * retrieve information about the error (such as a string describing the error, * the system errno(7) value associated with the error, etc), use * pathrs_errorinfo(). */ int pathrs_proc_readlinkat(int proc_rootfd, pathrs_proc_base_t base, const char *path, char *linkbuf, size_t linkbuf_size); /** * Safely read the contents of a symlink inside `/proc`. * * As with `pathrs_proc_open`, any bind-mounts or other over-mounts will * (depending on what kernel features are available) be detected and an error * will be returned. Non-trailing symlinks are followed but care is taken to * ensure the symlinks are legitimate. * * This function is effectively shorthand for * * ```c * fd = pathrs_proc_open(base, path, O_PATH|O_NOFOLLOW); * if (IS_PATHRS_ERR(fd)) { * liberr = fd; // for use with pathrs_errorinfo() * goto err; * } * copied = readlinkat(fd, "", linkbuf, linkbuf_size); * close(fd); * ``` * * # Return Value * * On success, this function copies the symlink contents to `linkbuf` (up to * `linkbuf_size` bytes) and returns the full size of the symlink path buffer. * This function will not copy the trailing NUL byte, and the return size does * not include the NUL byte. A `NULL` `linkbuf` or invalid `linkbuf_size` are * treated as zero-size buffers. * * NOTE: Unlike readlinkat(2), in the case where linkbuf is too small to * contain the symlink contents, pathrs_proc_readlink() will return *the number * of bytes it would have copied if the buffer was large enough*. This matches * the behaviour of pathrs_inroot_readlink(). * * If an error occurs, this function will return a negative error code. To * retrieve information about the error (such as a string describing the error, * the system errno(7) value associated with the error, etc), use * pathrs_errorinfo(). */ int pathrs_proc_readlink(pathrs_proc_base_t base, const char *path, char *linkbuf, size_t linkbuf_size); /** * Retrieve error information about an error id returned by a pathrs operation. * * Whenever an error occurs with libpathrs, a negative number describing that * error (the error id) is returned. pathrs_errorinfo() is used to retrieve * that information: * * ```c * fd = pathrs_inroot_resolve(root, "/foo/bar"); * if (IS_PATHRS_ERR(fd)) { * // fd is an error id * pathrs_error_t *error = pathrs_errorinfo(fd); * // ... print the error information ... * pathrs_errorinfo_free(error); * } * ``` * * Once pathrs_errorinfo() is called for a particular error id, that error id * is no longer valid and should not be used for subsequent pathrs_errorinfo() * calls. * * Error ids are only unique from one another until pathrs_errorinfo() is * called, at which point the id can be reused for subsequent errors. The * precise format of error ids is completely opaque and they should never be * compared directly or used for anything other than with pathrs_errorinfo(). * * Error ids are not thread-specific and thus pathrs_errorinfo() can be called * on a different thread to the thread where the operation failed (this is of * particular note to green-thread language bindings like Go, where this is * important). * * # Return Value * * If there was a saved error with the provided id, a pathrs_error_t is * returned describing the error. Use pathrs_errorinfo_free() to free the * associated memory once you are done with the error. */ pathrs_error_t *pathrs_errorinfo(int err_id); /** * Free the pathrs_error_t object returned by pathrs_errorinfo(). */ void pathrs_errorinfo_free(pathrs_error_t *ptr); /** * Return the version information of the libpathrs library at runtime. * * This API is designed to be extensible. The caller must pass a pointer to a * contiguous buffer `dst` that is large enough to store `dst_size` bytes. This * buffer is then filled with version information. If the library has less data * than the given buffer size, the trailing bytes are zero-filled. If the * library has more data than the given buffer size the data is truncated and * (if the truncated data contained non-zero values), the return value * indicates what buffer size is needed to contain all version data. * * # Return Value * * On success, this function returns `0` or (if the version data was truncated) * a positive integer that is the size of the buffer needed to store all data. * * If an error occurs, this function will return a negative error code. To * retrieve information about the error (such as a string describing the error, * the system errno(7) value associated with the error, etc), use * pathrs_errorinfo(). */ int pathrs_version(pathrs_version_info_t *dst, size_t dst_size); #endif /* LIBPATHRS_H */ #ifdef __CBINDGEN_ALIGNED #undef __CBINDGEN_ALIGNED #endif