Coverage Report

Created: 2026-02-26 06:23

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