]> git.ipfire.org Git - thirdparty/util-linux.git/blob - include/mount-api-utils.h
8dbe534672438b9e74069f1505cde739c74111f1
[thirdparty/util-linux.git] / include / mount-api-utils.h
1 /*
2 * No copyright is claimed. This code is in the public domain; do with
3 * it what you wish.
4 */
5 #ifndef UTIL_LINUX_MOUNT_API_UTILS
6 #define UTIL_LINUX_MOUNT_API_UTILS
7
8 #ifdef HAVE_LINUX_MOUNT_H
9 #include <sys/mount.h>
10 #include <linux/mount.h>
11 #include <linux/unistd.h>
12 #include <sys/syscall.h>
13 #include <inttypes.h>
14
15 /*
16 * File descritors based mount API
17 */
18 #ifdef HAVE_MOUNTFD_API
19
20 /* Accepted by both open_tree() and mount_setattr(). */
21 #ifndef AT_RECURSIVE
22 # define AT_RECURSIVE 0x8000
23 #endif
24
25 #ifndef OPEN_TREE_CLONE
26 # define OPEN_TREE_CLONE 1
27 #endif
28
29 #ifndef OPEN_TREE_CLOEXEC
30 # define OPEN_TREE_CLOEXEC O_CLOEXEC
31 #endif
32
33 #if !defined(HAVE_OPEN_TREE) && defined(SYS_open_tree)
34 static inline int open_tree(int dfd, const char *filename, unsigned int flags)
35 {
36 return syscall(SYS_open_tree, dfd, filename, flags);
37 }
38 #endif
39
40 #ifndef MOVE_MOUNT_F_SYMLINKS
41 # define MOVE_MOUNT_F_SYMLINKS 0x00000001 /* Follow symlinks on from path */
42 #endif
43
44 #ifndef MOVE_MOUNT_F_AUTOMOUNTS
45 # define MOVE_MOUNT_F_AUTOMOUNTS 0x00000002 /* Follow automounts on from path */
46 #endif
47
48 #ifndef MOVE_MOUNT_F_EMPTY_PATH
49 # define MOVE_MOUNT_F_EMPTY_PATH 0x00000004 /* Empty from path permitted */
50 #endif
51
52 #ifndef MOVE_MOUNT_T_SYMLINKS
53 # define MOVE_MOUNT_T_SYMLINKS 0x00000010 /* Follow symlinks on to path */
54 #endif
55
56 #ifndef MOVE_MOUNT_T_AUTOMOUNTS
57 # define MOVE_MOUNT_T_AUTOMOUNTS 0x00000020 /* Follow automounts on to path */
58 #endif
59
60 #ifndef MOVE_MOUNT_T_EMPTY_PATH
61 # define MOVE_MOUNT_T_EMPTY_PATH 0x00000040 /* Empty to path permitted */
62 #endif
63
64 #ifndef MOVE_MOUNT_SET_GROUP
65 # define MOVE_MOUNT_SET_GROUP 0x00000100 /* Set sharing group instead */
66 #endif
67
68 #ifndef MOVE_MOUNT__MASK
69 # define MOVE_MOUNT__MASK 0x00000077
70 #endif
71
72 #if !defined(HAVE_MOVE_MOUNT) && defined(SYS_move_mount)
73 static inline int move_mount(int from_dfd, const char *from_pathname, int to_dfd,
74 const char *to_pathname, unsigned int flags)
75 {
76 return syscall(SYS_move_mount, from_dfd, from_pathname, to_dfd,
77 to_pathname, flags);
78 }
79 #endif
80
81 #ifndef MOUNT_ATTR_RDONLY
82 # define MOUNT_ATTR_RDONLY 0x00000001
83 #endif
84
85 #ifndef MOUNT_ATTR_NOSUID
86 # define MOUNT_ATTR_NOSUID 0x00000002
87 #endif
88
89 #ifndef MOUNT_ATTR_NODEV
90 # define MOUNT_ATTR_NODEV 0x00000004
91 #endif
92
93 #ifndef MOUNT_ATTR_NOEXEC
94 # define MOUNT_ATTR_NOEXEC 0x00000008
95 #endif
96
97 #ifndef MOUNT_ATTR__ATIME
98 # define MOUNT_ATTR__ATIME 0x00000070
99 #endif
100
101 #ifndef MOUNT_ATTR_RELATIME
102 # define MOUNT_ATTR_RELATIME 0x00000000
103 #endif
104
105 #ifndef MOUNT_ATTR_NOATIME
106 # define MOUNT_ATTR_NOATIME 0x00000010
107 #endif
108
109 #ifndef MOUNT_ATTR_STRICTATIME
110 # define MOUNT_ATTR_STRICTATIME 0x00000020
111 #endif
112
113 #ifndef MOUNT_ATTR_NODIRATIME
114 # define MOUNT_ATTR_NODIRATIME 0x00000080
115 #endif
116
117 #ifndef MOUNT_ATTR_IDMAP
118 # define MOUNT_ATTR_IDMAP 0x00100000
119 #endif
120
121 #ifndef MOUNT_ATTR_NOSYMFOLLOW
122 # define MOUNT_ATTR_NOSYMFOLLOW 0x00200000
123 #endif
124
125 #ifndef HAVE_STRUCT_MOUNT_ATTR
126 # ifndef MOUNT_ATTR_SIZE_VER0 /* For case mount.h comes from a place invisible for autotools/meson */
127 # include <inttypes.h>
128 struct mount_attr {
129 uint64_t attr_set;
130 uint64_t attr_clr;
131 uint64_t propagation;
132 uint64_t userns_fd;
133 };
134 # endif
135 #endif
136
137 #if !defined(HAVE_MOUNT_SETATTR) && defined(SYS_mount_setattr)
138 static inline int mount_setattr(int dfd, const char *path, unsigned int flags,
139 struct mount_attr *attr, size_t size)
140 {
141 return syscall(SYS_mount_setattr, dfd, path, flags, attr, size);
142 }
143 #endif
144
145 #ifndef HAVE_ENUM_FSCONFIG_COMMAND
146 # ifndef FSOPEN_CLOEXEC /* For case mount.h comes from a place invisible for autotools/meson */
147 enum fsconfig_command {
148 FSCONFIG_SET_FLAG = 0, /* Set parameter, supplying no value */
149 FSCONFIG_SET_STRING = 1, /* Set parameter, supplying a string value */
150 FSCONFIG_SET_BINARY = 2, /* Set parameter, supplying a binary blob value */
151 FSCONFIG_SET_PATH = 3, /* Set parameter, supplying an object by path */
152 FSCONFIG_SET_PATH_EMPTY = 4, /* Set parameter, supplying an object by (empty) path */
153 FSCONFIG_SET_FD = 5, /* Set parameter, supplying an object by fd */
154 FSCONFIG_CMD_CREATE = 6, /* Invoke superblock creation */
155 FSCONFIG_CMD_RECONFIGURE = 7, /* Invoke superblock reconfiguration */
156 };
157 # endif
158 #endif
159
160 #if !defined(HAVE_FSCONFIG) && defined(SYS_fsconfig)
161 static inline int fsconfig(int fd, unsigned int cmd, const char *key,
162 const void *value, int aux)
163 {
164 return syscall(SYS_fsconfig, fd, cmd, key, value, aux);
165 }
166 #endif
167
168 #ifndef FSOPEN_CLOEXEC
169 # define FSOPEN_CLOEXEC 0x00000001
170 #endif
171
172 #if !defined(HAVE_FSOPEN) && defined(SYS_fsopen)
173 static inline int fsopen(const char *fsname, unsigned int flags)
174 {
175 return syscall(SYS_fsopen, fsname, flags);
176 }
177 #endif
178
179 #ifndef FSMOUNT_CLOEXEC
180 # define FSMOUNT_CLOEXEC 0x00000001
181 #endif
182
183 #if !defined(HAVE_FSMOUNT) && defined(SYS_fsmount)
184 static inline int fsmount(int fd, unsigned int flags, unsigned int mount_attrs)
185 {
186 return syscall(SYS_fsmount, fd, flags, mount_attrs);
187 }
188 #endif
189
190 #ifndef FSPICK_CLOEXEC
191 # define FSPICK_CLOEXEC 0x00000001
192 #endif
193
194 #ifndef FSPICK_SYMLINK_NOFOLLOW
195 # define FSPICK_SYMLINK_NOFOLLOW 0x00000002
196 #endif
197
198 #ifndef FSPICK_NO_AUTOMOUNT
199 # define FSPICK_NO_AUTOMOUNT 0x00000004
200 #endif
201
202 #ifdef FSPICK_EMPTY_PATH
203 # define FSPICK_EMPTY_PATH 0x00000008
204 #endif
205
206 #if !defined(HAVE_FSPICK) && defined(SYS_fspick)
207 static inline int fspick(int dfd, const char *pathname, unsigned int flags)
208 {
209 return syscall(SYS_fspick, dfd, pathname, flags);
210 }
211 #endif
212
213 #endif /* HAVE_MOUNTFD_API */
214
215 /*
216 * statmount() and listmount()
217 */
218 #ifdef HAVE_STATMOUNT_API
219
220 #ifndef MNT_ID_REQ_SIZE_VER0
221 # define MNT_ID_REQ_SIZE_VER0 24 /* sizeof first published struct */
222 #endif
223 #ifndef MNT_ID_REQ_SIZE_VER1
224 # define MNT_ID_REQ_SIZE_VER1 32 /* sizeof second published struct */
225 #endif
226
227 /*
228 * The structs mnt_id_req and statmount may differ between kernel versions, so
229 * we must ensure that the structs contain everything we need. For now (during
230 * development), it seems best to define local copies of the structs to avoid
231 * relying on installed kernel headers and to avoid a storm of #ifdefs.
232 */
233
234 /*
235 * listmount() and statmount() request
236 */
237 struct ul_mnt_id_req {
238 uint32_t size;
239 uint32_t spare;
240 uint64_t mnt_id;
241 uint64_t param;
242 uint64_t mnt_ns_id;
243 };
244
245 /*
246 * Please note that due to the variable length of the statmount buffer, the
247 * struct cannot be versioned by size (like struct mnt_id_req).
248 */
249 struct ul_statmount {
250 uint32_t size; /* Total size, including strings */
251 uint32_t mnt_opts; /* [str] Mount options of the mount */
252 uint64_t mask; /* What results were written */
253 uint32_t sb_dev_major; /* Device ID */
254 uint32_t sb_dev_minor;
255 uint64_t sb_magic; /* ..._SUPER_MAGIC */
256 uint32_t sb_flags; /* SB_{RDONLY,SYNCHRONOUS,DIRSYNC,LAZYTIME} */
257 uint32_t fs_type; /* [str] Filesystem type */
258 uint64_t mnt_id; /* Unique ID of mount */
259 uint64_t mnt_parent_id; /* Unique ID of parent (for root == mnt_id) */
260 uint32_t mnt_id_old; /* Reused IDs used in proc/.../mountinfo */
261 uint32_t mnt_parent_id_old;
262 uint64_t mnt_attr; /* MOUNT_ATTR_... */
263 uint64_t mnt_propagation; /* MS_{SHARED,SLAVE,PRIVATE,UNBINDABLE} */
264 uint64_t mnt_peer_group; /* ID of shared peer group */
265 uint64_t mnt_master; /* Mount receives propagation from this ID */
266 uint64_t propagate_from; /* Propagation from in current namespace */
267 uint32_t mnt_root; /* [str] Root of mount relative to root of fs */
268 uint32_t mnt_point; /* [str] Mountpoint relative to current root */
269 uint64_t mnt_ns_id; /* ID of the mount namespace */
270 uint32_t fs_subtype; /* [str] Subtype of fs_type (if any) */
271 uint32_t sb_source; /* [str] Source string of the mount */
272 uint32_t opt_num; /* Number of fs options */
273 uint32_t opt_array; /* [str] Array of nul terminated fs options */
274 uint32_t opt_sec_num; /* Number of security options */
275 uint32_t opt_sec_array; /* [str] Array of nul terminated security options */
276 uint64_t __spare2[46];
277 char str[]; /* Variable size part containing strings */
278 };
279
280 /* sb_flags (defined in kernel include/linux/fs.h) */
281 #ifndef SB_RDONLY
282 # define SB_RDONLY BIT(0) /* Mount read-only */
283 # define SB_NOSUID BIT(1) /* Ignore suid and sgid bits */
284 # define SB_NODEV BIT(2) /* Disallow access to device special files */
285 # define SB_NOEXEC BIT(3) /* Disallow program execution */
286 # define SB_SYNCHRONOUS BIT(4) /* Writes are synced at once */
287 # define SB_MANDLOCK BIT(6) /* Allow mandatory locks on an FS */
288 # define SB_DIRSYNC BIT(7) /* Directory modifications are synchronous */
289 # define SB_NOATIME BIT(10) /* Do not update access times. */
290 # define SB_NODIRATIME BIT(11) /* Do not update directory access times */
291 # define SB_SILENT BIT(15)
292 # define SB_POSIXACL BIT(16) /* Supports POSIX ACLs */
293 # define SB_INLINECRYPT BIT(17) /* Use blk-crypto for encrypted files */
294 # define SB_KERNMOUNT BIT(22) /* this is a kern_mount call */
295 # define SB_I_VERSION BIT(23) /* Update inode I_version field */
296 # define SB_LAZYTIME BIT(25) /* Update the on-disk [acm]times lazily */
297 #endif
298
299 /*
300 * @mask bits for statmount(2)
301 */
302 #ifndef STATMOUNT_SB_BASIC
303 # define STATMOUNT_SB_BASIC 0x00000001U /* Want/got sb_... */
304 #endif
305 #ifndef STATMOUNT_MNT_BASIC
306 # define STATMOUNT_MNT_BASIC 0x00000002U /* Want/got mnt_... */
307 #endif
308 #ifndef STATMOUNT_PROPAGATE_FROM
309 # define STATMOUNT_PROPAGATE_FROM 0x00000004U /* Want/got propagate_from */
310 #endif
311 #ifndef STATMOUNT_MNT_ROOT
312 # define STATMOUNT_MNT_ROOT 0x00000008U /* Want/got mnt_root */
313 #endif
314 #ifndef STATMOUNT_MNT_POINT
315 # define STATMOUNT_MNT_POINT 0x00000010U /* Want/got mnt_point */
316 #endif
317 #ifndef STATMOUNT_FS_TYPE
318 # define STATMOUNT_FS_TYPE 0x00000020U /* Want/got fs_type */
319 #endif
320 #ifndef STATMOUNT_MNT_NS_ID
321 # define STATMOUNT_MNT_NS_ID 0x00000040U /* Want/got mnt_ns_id */
322 #endif
323 #ifndef STATMOUNT_MNT_OPTS
324 # define STATMOUNT_MNT_OPTS 0x00000080U /* Want/got mnt_opts */
325 #endif
326 #ifndef STATMOUNT_FS_SUBTYPE
327 # define STATMOUNT_FS_SUBTYPE 0x00000100U /* Want/got fs_subtype */
328 #endif
329 #ifndef STATMOUNT_SB_SOURCE
330 # define STATMOUNT_SB_SOURCE 0x00000200U /* Want/got sb_source */
331 #endif
332 #ifndef STATMOUNT_OPT_ARRAY
333 # define STATMOUNT_OPT_ARRAY 0x00000400U /* Want/got opt_... */
334 #endif
335 #ifndef STATMOUNT_OPT_SEC_ARRAY
336 # define STATMOUNT_OPT_SEC_ARRAY 0x00000800U /* Want/got opt_sec... */
337 #endif
338
339
340 /*
341 * Special @mnt_id values that can be passed to listmount
342 */
343 #ifdef LSMT_ROOT
344 # define LSMT_ROOT 0xffffffffffffffff /* root mount */
345 #endif
346
347 #ifndef LISTMOUNT_REVERSE
348 # define LISTMOUNT_REVERSE BIT(0) /* List later mounts first */
349 #endif
350
351 /* Don't use this "raw" version. See ul_statmount() below. */
352 #if defined(SYS_statmount)
353 static inline int ul_statmount_syscall(uint64_t mnt_id,
354 uint64_t ns_id,
355 uint64_t mask,
356 struct ul_statmount *buf,
357 size_t bufsize, unsigned int flags)
358 {
359 struct ul_mnt_id_req req = {
360 .size = MNT_ID_REQ_SIZE_VER1,
361 .mnt_id = mnt_id,
362 .param = mask,
363 .mnt_ns_id = ns_id
364 };
365
366 return syscall(SYS_statmount, &req, buf, bufsize, flags);
367 }
368
369 static inline int has_statmount(void)
370 {
371 errno = 0;
372
373 if (ul_statmount_syscall(0, 0, 0, NULL, 0, 0) < 0 && errno == ENOSYS)
374 return 0;
375 return 1;
376 }
377
378 /* This is a version of statmount() that reallocates @buf to be large enough to
379 * store data for the requested @id. This function never deallocates; it is the
380 * caller's responsibility.
381 */
382 static inline int ul_statmount(uint64_t id,
383 uint64_t ns_id,
384 uint64_t mask,
385 struct ul_statmount **buf,
386 size_t *bufsiz,
387 unsigned int flags)
388 {
389 size_t sz;
390 int rc = 0;
391
392 if (!buf || !bufsiz)
393 return -EINVAL;
394
395 sz = *bufsiz;
396 if (!sz)
397 sz = 32 * 1024;
398
399 do {
400 if (sz > *bufsiz) {
401 struct ul_statmount *tmp = realloc(*buf, sz);
402 if (!tmp)
403 return -ENOMEM;
404 *buf = tmp;
405 *bufsiz = sz;
406 }
407
408 errno = 0;
409 rc = ul_statmount_syscall(id, ns_id, mask, *buf, *bufsiz, flags);
410 if (!rc)
411 break;
412 if (errno != EOVERFLOW)
413 break;
414 if (sz >= SIZE_MAX / 2)
415 break;
416 sz <<= 1;
417 } while (rc);
418
419 return rc;
420 }
421 #endif /* SYS_statmount */
422
423
424 #if defined(SYS_listmount)
425 static inline ssize_t ul_listmount(uint64_t mnt_id,
426 uint64_t ns_id,
427 uint64_t last_mnt_id,
428 uint64_t list[], size_t num,
429 unsigned int flags)
430 {
431 struct ul_mnt_id_req req = {
432 .size = MNT_ID_REQ_SIZE_VER1,
433 .mnt_id = mnt_id,
434 .param = last_mnt_id,
435 .mnt_ns_id = ns_id
436 };
437
438 return syscall(SYS_listmount, &req, list, num, flags);
439 }
440
441 static inline int has_listmount(void)
442 {
443 uint64_t dummy;
444
445 errno = 0;
446
447 if (ul_listmount(LSMT_ROOT, 0, 0, &dummy, 1, LISTMOUNT_REVERSE) != 1)
448 return 0;
449 return 1;
450 }
451 #endif
452
453 #endif /* HAVE_STATMOUNT_API */
454
455 #endif /* HAVE_LINUX_MOUNT_H */
456
457 #endif /* UTIL_LINUX_MOUNT_API_UTILS */