Coverage Report

Created: 2026-06-10 06:32

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