1
0
Fork 0
util-linux/include/mount-api-utils.h
Daniel Baumann c36e531662
Adding upstream version 2.41.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-21 11:26:35 +02:00

434 lines
12 KiB
C

/*
* No copyright is claimed. This code is in the public domain; do with
* it what you wish.
*/
#ifndef UTIL_LINUX_MOUNT_API_UTILS
#define UTIL_LINUX_MOUNT_API_UTILS
#ifdef HAVE_LINUX_MOUNT_H
#include <sys/mount.h>
#include <linux/mount.h>
#include <sys/syscall.h>
#include <inttypes.h>
/*
* File descritors based mount API
*/
#ifdef HAVE_MOUNTFD_API
/* Accepted by both open_tree() and mount_setattr(). */
#ifndef AT_RECURSIVE
# define AT_RECURSIVE 0x8000
#endif
#ifndef OPEN_TREE_CLONE
# define OPEN_TREE_CLONE 1
#endif
#ifndef OPEN_TREE_CLOEXEC
# define OPEN_TREE_CLOEXEC O_CLOEXEC
#endif
#if !defined(HAVE_OPEN_TREE) && defined(SYS_open_tree)
static inline int open_tree(int dfd, const char *filename, unsigned int flags)
{
return syscall(SYS_open_tree, dfd, filename, flags);
}
#endif
#ifndef MOVE_MOUNT_F_SYMLINKS
# define MOVE_MOUNT_F_SYMLINKS 0x00000001 /* Follow symlinks on from path */
#endif
#ifndef MOVE_MOUNT_F_AUTOMOUNTS
# define MOVE_MOUNT_F_AUTOMOUNTS 0x00000002 /* Follow automounts on from path */
#endif
#ifndef MOVE_MOUNT_F_EMPTY_PATH
# define MOVE_MOUNT_F_EMPTY_PATH 0x00000004 /* Empty from path permitted */
#endif
#ifndef MOVE_MOUNT_T_SYMLINKS
# define MOVE_MOUNT_T_SYMLINKS 0x00000010 /* Follow symlinks on to path */
#endif
#ifndef MOVE_MOUNT_T_AUTOMOUNTS
# define MOVE_MOUNT_T_AUTOMOUNTS 0x00000020 /* Follow automounts on to path */
#endif
#ifndef MOVE_MOUNT_T_EMPTY_PATH
# define MOVE_MOUNT_T_EMPTY_PATH 0x00000040 /* Empty to path permitted */
#endif
#ifndef MOVE_MOUNT_SET_GROUP
# define MOVE_MOUNT_SET_GROUP 0x00000100 /* Set sharing group instead */
#endif
#ifndef MOVE_MOUNT__MASK
# define MOVE_MOUNT__MASK 0x00000077
#endif
#if !defined(HAVE_MOVE_MOUNT) && defined(SYS_move_mount)
static inline int move_mount(int from_dfd, const char *from_pathname, int to_dfd,
const char *to_pathname, unsigned int flags)
{
return syscall(SYS_move_mount, from_dfd, from_pathname, to_dfd,
to_pathname, flags);
}
#endif
#ifndef MOUNT_ATTR_RDONLY
# define MOUNT_ATTR_RDONLY 0x00000001
#endif
#ifndef MOUNT_ATTR_NOSUID
# define MOUNT_ATTR_NOSUID 0x00000002
#endif
#ifndef MOUNT_ATTR_NODEV
# define MOUNT_ATTR_NODEV 0x00000004
#endif
#ifndef MOUNT_ATTR_NOEXEC
# define MOUNT_ATTR_NOEXEC 0x00000008
#endif
#ifndef MOUNT_ATTR__ATIME
# define MOUNT_ATTR__ATIME 0x00000070
#endif
#ifndef MOUNT_ATTR_RELATIME
# define MOUNT_ATTR_RELATIME 0x00000000
#endif
#ifndef MOUNT_ATTR_NOATIME
# define MOUNT_ATTR_NOATIME 0x00000010
#endif
#ifndef MOUNT_ATTR_STRICTATIME
# define MOUNT_ATTR_STRICTATIME 0x00000020
#endif
#ifndef MOUNT_ATTR_NODIRATIME
# define MOUNT_ATTR_NODIRATIME 0x00000080
#endif
#ifndef MOUNT_ATTR_IDMAP
# define MOUNT_ATTR_IDMAP 0x00100000
#endif
#ifndef MOUNT_ATTR_NOSYMFOLLOW
# define MOUNT_ATTR_NOSYMFOLLOW 0x00200000
#endif
#ifndef HAVE_STRUCT_MOUNT_ATTR
# ifndef MOUNT_ATTR_SIZE_VER0 /* For case mount.h comes from a place invisible for autotools/meson */
# include <inttypes.h>
struct mount_attr {
uint64_t attr_set;
uint64_t attr_clr;
uint64_t propagation;
uint64_t userns_fd;
};
# endif
#endif
#if !defined(HAVE_MOUNT_SETATTR) && defined(SYS_mount_setattr)
static inline int mount_setattr(int dfd, const char *path, unsigned int flags,
struct mount_attr *attr, size_t size)
{
return syscall(SYS_mount_setattr, dfd, path, flags, attr, size);
}
#endif
#ifndef HAVE_ENUM_FSCONFIG_COMMAND
# ifndef FSOPEN_CLOEXEC /* For case mount.h comes from a place invisible for autotools/meson */
enum fsconfig_command {
FSCONFIG_SET_FLAG = 0, /* Set parameter, supplying no value */
FSCONFIG_SET_STRING = 1, /* Set parameter, supplying a string value */
FSCONFIG_SET_BINARY = 2, /* Set parameter, supplying a binary blob value */
FSCONFIG_SET_PATH = 3, /* Set parameter, supplying an object by path */
FSCONFIG_SET_PATH_EMPTY = 4, /* Set parameter, supplying an object by (empty) path */
FSCONFIG_SET_FD = 5, /* Set parameter, supplying an object by fd */
FSCONFIG_CMD_CREATE = 6, /* Invoke superblock creation */
FSCONFIG_CMD_RECONFIGURE = 7, /* Invoke superblock reconfiguration */
};
# endif
#endif
#if !defined(HAVE_FSCONFIG) && defined(SYS_fsconfig)
static inline int fsconfig(int fd, unsigned int cmd, const char *key,
const void *value, int aux)
{
return syscall(SYS_fsconfig, fd, cmd, key, value, aux);
}
#endif
#ifndef FSOPEN_CLOEXEC
# define FSOPEN_CLOEXEC 0x00000001
#endif
#if !defined(HAVE_FSOPEN) && defined(SYS_fsopen)
static inline int fsopen(const char *fsname, unsigned int flags)
{
return syscall(SYS_fsopen, fsname, flags);
}
#endif
#ifndef FSMOUNT_CLOEXEC
# define FSMOUNT_CLOEXEC 0x00000001
#endif
#if !defined(HAVE_FSMOUNT) && defined(SYS_fsmount)
static inline int fsmount(int fd, unsigned int flags, unsigned int mount_attrs)
{
return syscall(SYS_fsmount, fd, flags, mount_attrs);
}
#endif
#ifndef FSPICK_CLOEXEC
# define FSPICK_CLOEXEC 0x00000001
#endif
#ifndef FSPICK_SYMLINK_NOFOLLOW
# define FSPICK_SYMLINK_NOFOLLOW 0x00000002
#endif
#ifndef FSPICK_NO_AUTOMOUNT
# define FSPICK_NO_AUTOMOUNT 0x00000004
#endif
#ifdef FSPICK_EMPTY_PATH
# define FSPICK_EMPTY_PATH 0x00000008
#endif
#if !defined(HAVE_FSPICK) && defined(SYS_fspick)
static inline int fspick(int dfd, const char *pathname, unsigned int flags)
{
return syscall(SYS_fspick, dfd, pathname, flags);
}
#endif
#endif /* HAVE_MOUNTFD_API */
/*
* statmount() and listmount()
*/
#ifdef HAVE_STATMOUNT_API
#ifndef MNT_ID_REQ_SIZE_VER0
# define MNT_ID_REQ_SIZE_VER0 24 /* sizeof first published struct */
#endif
#ifndef MNT_ID_REQ_SIZE_VER1
# define MNT_ID_REQ_SIZE_VER1 32 /* sizeof second published struct */
#endif
/*
* The structs mnt_id_req and statmount may differ between kernel versions, so
* we must ensure that the structs contain everything we need. For now (during
* development), it seems best to define local copies of the structs to avoid
* relying on installed kernel headers and to avoid a storm of #ifdefs.
*/
/*
* listmount() and statmount() request
*/
struct ul_mnt_id_req {
uint32_t size;
uint32_t spare;
uint64_t mnt_id;
uint64_t param;
uint64_t mnt_ns_id;
};
/*
* Please note that due to the variable length of the statmount buffer, the
* struct cannot be versioned by size (like struct mnt_id_req).
*/
struct ul_statmount {
uint32_t size; /* Total size, including strings */
uint32_t mnt_opts; /* [str] Mount options of the mount */
uint64_t mask; /* What results were written */
uint32_t sb_dev_major; /* Device ID */
uint32_t sb_dev_minor;
uint64_t sb_magic; /* ..._SUPER_MAGIC */
uint32_t sb_flags; /* SB_{RDONLY,SYNCHRONOUS,DIRSYNC,LAZYTIME} */
uint32_t fs_type; /* [str] Filesystem type */
uint64_t mnt_id; /* Unique ID of mount */
uint64_t mnt_parent_id; /* Unique ID of parent (for root == mnt_id) */
uint32_t mnt_id_old; /* Reused IDs used in proc/.../mountinfo */
uint32_t mnt_parent_id_old;
uint64_t mnt_attr; /* MOUNT_ATTR_... */
uint64_t mnt_propagation; /* MS_{SHARED,SLAVE,PRIVATE,UNBINDABLE} */
uint64_t mnt_peer_group; /* ID of shared peer group */
uint64_t mnt_master; /* Mount receives propagation from this ID */
uint64_t propagate_from; /* Propagation from in current namespace */
uint32_t mnt_root; /* [str] Root of mount relative to root of fs */
uint32_t mnt_point; /* [str] Mountpoint relative to current root */
uint64_t mnt_ns_id; /* ID of the mount namespace */
uint32_t fs_subtype; /* [str] Subtype of fs_type (if any) */
uint32_t sb_source; /* [str] Source string of the mount */
uint32_t opt_num; /* Number of fs options */
uint32_t opt_array; /* [str] Array of nul terminated fs options */
uint32_t opt_sec_num; /* Number of security options */
uint32_t opt_sec_array; /* [str] Array of nul terminated security options */
uint64_t __spare2[46];
char str[]; /* Variable size part containing strings */
};
/* sb_flags (defined in kernel include/linux/fs.h) */
#ifndef SB_RDONLY
# define SB_RDONLY BIT(0) /* Mount read-only */
# define SB_NOSUID BIT(1) /* Ignore suid and sgid bits */
# define SB_NODEV BIT(2) /* Disallow access to device special files */
# define SB_NOEXEC BIT(3) /* Disallow program execution */
# define SB_SYNCHRONOUS BIT(4) /* Writes are synced at once */
# define SB_MANDLOCK BIT(6) /* Allow mandatory locks on an FS */
# define SB_DIRSYNC BIT(7) /* Directory modifications are synchronous */
# define SB_NOATIME BIT(10) /* Do not update access times. */
# define SB_NODIRATIME BIT(11) /* Do not update directory access times */
# define SB_SILENT BIT(15)
# define SB_POSIXACL BIT(16) /* Supports POSIX ACLs */
# define SB_INLINECRYPT BIT(17) /* Use blk-crypto for encrypted files */
# define SB_KERNMOUNT BIT(22) /* this is a kern_mount call */
# define SB_I_VERSION BIT(23) /* Update inode I_version field */
# define SB_LAZYTIME BIT(25) /* Update the on-disk [acm]times lazily */
#endif
/*
* @mask bits for statmount(2)
*/
#ifndef STATMOUNT_SB_BASIC
# define STATMOUNT_SB_BASIC 0x00000001U /* Want/got sb_... */
#endif
#ifndef STATMOUNT_MNT_BASIC
# define STATMOUNT_MNT_BASIC 0x00000002U /* Want/got mnt_... */
#endif
#ifndef STATMOUNT_PROPAGATE_FROM
# define STATMOUNT_PROPAGATE_FROM 0x00000004U /* Want/got propagate_from */
#endif
#ifndef STATMOUNT_MNT_ROOT
# define STATMOUNT_MNT_ROOT 0x00000008U /* Want/got mnt_root */
#endif
#ifndef STATMOUNT_MNT_POINT
# define STATMOUNT_MNT_POINT 0x00000010U /* Want/got mnt_point */
#endif
#ifndef STATMOUNT_FS_TYPE
# define STATMOUNT_FS_TYPE 0x00000020U /* Want/got fs_type */
#endif
#ifndef STATMOUNT_MNT_NS_ID
# define STATMOUNT_MNT_NS_ID 0x00000040U /* Want/got mnt_ns_id */
#endif
#ifndef STATMOUNT_MNT_OPTS
# define STATMOUNT_MNT_OPTS 0x00000080U /* Want/got mnt_opts */
#endif
#ifndef STATMOUNT_FS_SUBTYPE
# define STATMOUNT_FS_SUBTYPE 0x00000100U /* Want/got fs_subtype */
#endif
#ifndef STATMOUNT_SB_SOURCE
# define STATMOUNT_SB_SOURCE 0x00000200U /* Want/got sb_source */
#endif
#ifndef STATMOUNT_OPT_ARRAY
# define STATMOUNT_OPT_ARRAY 0x00000400U /* Want/got opt_... */
#endif
#ifndef STATMOUNT_OPT_SEC_ARRAY
# define STATMOUNT_OPT_SEC_ARRAY 0x00000800U /* Want/got opt_sec... */
#endif
/*
* Special @mnt_id values that can be passed to listmount
*/
#ifdef LSMT_ROOT
# define LSMT_ROOT 0xffffffffffffffff /* root mount */
#endif
#ifndef LISTMOUNT_REVERSE
# define LISTMOUNT_REVERSE BIT(0) /* List later mounts first */
#endif
#if defined(SYS_statmount)
static inline int ul_statmount(uint64_t mnt_id,
uint64_t ns_id,
uint64_t mask,
struct ul_statmount *buf,
size_t bufsize, unsigned int flags)
{
struct ul_mnt_id_req req = {
.size = MNT_ID_REQ_SIZE_VER1,
.mnt_id = mnt_id,
.param = mask,
.mnt_ns_id = ns_id
};
return syscall(SYS_statmount, &req, buf, bufsize, flags);
}
#endif
#if defined(SYS_listmount)
static inline ssize_t ul_listmount(uint64_t mnt_id,
uint64_t ns_id,
uint64_t last_mnt_id,
uint64_t list[], size_t num,
unsigned int flags)
{
struct ul_mnt_id_req req = {
.size = MNT_ID_REQ_SIZE_VER1,
.mnt_id = mnt_id,
.param = last_mnt_id,
.mnt_ns_id = ns_id
};
return syscall(SYS_listmount, &req, list, num, flags);
}
#endif
/* This is a version of statmount() that reallocates @buf to be large enough to
* store data for the requested @id. This function never deallocates; it is the
* caller's responsibility.
*/
static inline int sys_statmount(uint64_t id,
uint64_t ns_id,
uint64_t mask,
struct ul_statmount **buf,
size_t *bufsiz,
unsigned int flags)
{
size_t sz;
int rc = 0;
if (!buf || !bufsiz)
return -EINVAL;
sz = *bufsiz;
if (!sz)
sz = 32 * 1024;
do {
if (sz > *bufsiz) {
struct ul_statmount *tmp = realloc(*buf, sz);
if (!tmp)
return -ENOMEM;
*buf = tmp;
*bufsiz = sz;
}
errno = 0;
rc = ul_statmount(id, ns_id, mask, *buf, *bufsiz, flags);
if (!rc)
break;
if (errno != EOVERFLOW)
break;
if (sz >= SIZE_MAX / 2)
break;
sz <<= 1;
} while (rc);
return rc;
}
#endif /* HAVE_STATMOUNT_API */
#endif /* HAVE_LINUX_MOUNT_H */
#endif /* UTIL_LINUX_MOUNT_API_UTILS */