mountfd 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,197 @@
1
+ #ifndef MOUNTFD_COMPAT_H
2
+ #define MOUNTFD_COMPAT_H
3
+
4
+ #ifdef __linux__
5
+ # include <fcntl.h>
6
+ # include <stdint.h>
7
+ # include <sys/ioctl.h>
8
+ # include <sys/syscall.h>
9
+ # ifdef HAVE_LINUX_MOUNT_H
10
+ # include <linux/mount.h>
11
+ # endif
12
+
13
+ # ifndef SYS_open_tree
14
+ # define SYS_open_tree 428
15
+ # endif
16
+ # ifndef SYS_move_mount
17
+ # define SYS_move_mount 429
18
+ # endif
19
+ # ifndef SYS_fsopen
20
+ # define SYS_fsopen 430
21
+ # endif
22
+ # ifndef SYS_fsconfig
23
+ # define SYS_fsconfig 431
24
+ # endif
25
+ # ifndef SYS_fsmount
26
+ # define SYS_fsmount 432
27
+ # endif
28
+ # ifndef SYS_fspick
29
+ # define SYS_fspick 433
30
+ # endif
31
+ # ifndef SYS_mount_setattr
32
+ # define SYS_mount_setattr 442
33
+ # endif
34
+ # ifndef SYS_statmount
35
+ # define SYS_statmount 457
36
+ # endif
37
+ # ifndef SYS_listmount
38
+ # define SYS_listmount 458
39
+ # endif
40
+ # ifndef SYS_pivot_root
41
+ # ifdef __NR_pivot_root
42
+ # define SYS_pivot_root __NR_pivot_root
43
+ # elif defined(__x86_64__)
44
+ # define SYS_pivot_root 155
45
+ # elif defined(__aarch64__)
46
+ # define SYS_pivot_root 41
47
+ # else
48
+ # error "SYS_pivot_root is unavailable for this architecture"
49
+ # endif
50
+ # endif
51
+
52
+ # ifndef FSOPEN_CLOEXEC
53
+ # define FSOPEN_CLOEXEC 0x00000001
54
+ # endif
55
+ # ifndef FSPICK_CLOEXEC
56
+ # define FSPICK_CLOEXEC 0x00000001
57
+ # define FSPICK_SYMLINK_NOFOLLOW 0x00000002
58
+ # define FSPICK_NO_AUTOMOUNT 0x00000004
59
+ # define FSPICK_EMPTY_PATH 0x00000008
60
+ # endif
61
+ # ifndef FSCONFIG_SET_FLAG
62
+ # define FSCONFIG_SET_FLAG 0
63
+ # define FSCONFIG_SET_STRING 1
64
+ # define FSCONFIG_SET_BINARY 2
65
+ # define FSCONFIG_SET_PATH 3
66
+ # define FSCONFIG_SET_PATH_EMPTY 4
67
+ # define FSCONFIG_SET_FD 5
68
+ # define FSCONFIG_CMD_CREATE 6
69
+ # define FSCONFIG_CMD_RECONFIGURE 7
70
+ # endif
71
+ # ifndef FSCONFIG_CMD_CREATE_EXCL
72
+ # define FSCONFIG_CMD_CREATE_EXCL 8
73
+ # endif
74
+ # ifndef FSMOUNT_CLOEXEC
75
+ # define FSMOUNT_CLOEXEC 0x00000001
76
+ # endif
77
+ # ifndef OPEN_TREE_CLONE
78
+ # define OPEN_TREE_CLONE 1
79
+ # endif
80
+ # ifndef OPEN_TREE_CLOEXEC
81
+ # define OPEN_TREE_CLOEXEC O_CLOEXEC
82
+ # endif
83
+ # ifndef MOVE_MOUNT_F_SYMLINKS
84
+ # define MOVE_MOUNT_F_SYMLINKS 0x00000001
85
+ # define MOVE_MOUNT_F_AUTOMOUNTS 0x00000002
86
+ # define MOVE_MOUNT_F_EMPTY_PATH 0x00000004
87
+ # define MOVE_MOUNT_T_SYMLINKS 0x00000010
88
+ # define MOVE_MOUNT_T_AUTOMOUNTS 0x00000020
89
+ # define MOVE_MOUNT_T_EMPTY_PATH 0x00000040
90
+ # endif
91
+ # ifndef MOVE_MOUNT_SET_GROUP
92
+ # define MOVE_MOUNT_SET_GROUP 0x00000100
93
+ # endif
94
+ # ifndef MOVE_MOUNT_BENEATH
95
+ # define MOVE_MOUNT_BENEATH 0x00000200
96
+ # endif
97
+ # ifndef MOUNT_ATTR_RDONLY
98
+ # define MOUNT_ATTR_RDONLY 0x00000001ULL
99
+ # define MOUNT_ATTR_NOSUID 0x00000002ULL
100
+ # define MOUNT_ATTR_NODEV 0x00000004ULL
101
+ # define MOUNT_ATTR_NOEXEC 0x00000008ULL
102
+ # define MOUNT_ATTR__ATIME 0x00000070ULL
103
+ # define MOUNT_ATTR_RELATIME 0x00000000ULL
104
+ # define MOUNT_ATTR_NOATIME 0x00000010ULL
105
+ # define MOUNT_ATTR_STRICTATIME 0x00000020ULL
106
+ # define MOUNT_ATTR_NODIRATIME 0x00000080ULL
107
+ # endif
108
+ # ifndef MOUNT_ATTR_IDMAP
109
+ # define MOUNT_ATTR_IDMAP 0x00100000ULL
110
+ # endif
111
+ # ifndef MOUNT_ATTR_NOSYMFOLLOW
112
+ # define MOUNT_ATTR_NOSYMFOLLOW 0x00200000ULL
113
+ # endif
114
+ # ifndef MOUNT_ATTR_SIZE_VER0
115
+ # define MOUNT_ATTR_SIZE_VER0 32
116
+ struct mount_attr {
117
+ uint64_t attr_set;
118
+ uint64_t attr_clr;
119
+ uint64_t propagation;
120
+ uint64_t userns_fd;
121
+ };
122
+ # endif
123
+ # ifndef AT_RECURSIVE
124
+ # define AT_RECURSIVE 0x8000
125
+ # endif
126
+ # ifndef AT_EMPTY_PATH
127
+ # define AT_EMPTY_PATH 0x1000
128
+ # endif
129
+ # ifndef MS_UNBINDABLE
130
+ # define MS_UNBINDABLE (1 << 17)
131
+ # endif
132
+ # ifndef MS_REC
133
+ # define MS_REC 16384
134
+ # endif
135
+ # ifndef MS_PRIVATE
136
+ # define MS_PRIVATE (1 << 18)
137
+ # endif
138
+ # ifndef MS_SLAVE
139
+ # define MS_SLAVE (1 << 19)
140
+ # endif
141
+ # ifndef MS_SHARED
142
+ # define MS_SHARED (1 << 20)
143
+ # endif
144
+ # ifndef CLONE_NEWNS
145
+ # define CLONE_NEWNS 0x00020000
146
+ # endif
147
+ # ifndef CLONE_NEWUSER
148
+ # define CLONE_NEWUSER 0x10000000
149
+ # endif
150
+ # ifndef NSIO
151
+ # define NSIO 0xb7
152
+ # endif
153
+ # ifndef NS_GET_MNTNS_ID
154
+ # define NS_GET_MNTNS_ID _IOR(NSIO, 0x5, uint64_t)
155
+ # endif
156
+ # ifndef MNT_ID_REQ_SIZE_VER0
157
+ # define MNT_ID_REQ_SIZE_VER0 24
158
+ # endif
159
+ # ifndef MNT_ID_REQ_SIZE_VER1
160
+ # define MNT_ID_REQ_SIZE_VER1 32
161
+ # endif
162
+ # ifndef STATMOUNT_SB_BASIC
163
+ # define STATMOUNT_SB_BASIC 0x00000001U
164
+ # endif
165
+ # ifndef STATMOUNT_MNT_BASIC
166
+ # define STATMOUNT_MNT_BASIC 0x00000002U
167
+ # endif
168
+ # ifndef STATMOUNT_PROPAGATE_FROM
169
+ # define STATMOUNT_PROPAGATE_FROM 0x00000004U
170
+ # endif
171
+ # ifndef STATMOUNT_MNT_ROOT
172
+ # define STATMOUNT_MNT_ROOT 0x00000008U
173
+ # endif
174
+ # ifndef STATMOUNT_MNT_POINT
175
+ # define STATMOUNT_MNT_POINT 0x00000010U
176
+ # endif
177
+ # ifndef STATMOUNT_FS_TYPE
178
+ # define STATMOUNT_FS_TYPE 0x00000020U
179
+ # endif
180
+ # ifndef STATMOUNT_MNT_NS_ID
181
+ # define STATMOUNT_MNT_NS_ID 0x00000040U
182
+ # endif
183
+ # ifndef STATMOUNT_MNT_OPTS
184
+ # define STATMOUNT_MNT_OPTS 0x00000080U
185
+ # endif
186
+ # ifndef STATMOUNT_FS_SUBTYPE
187
+ # define STATMOUNT_FS_SUBTYPE 0x00000100U
188
+ # endif
189
+ # ifndef STATMOUNT_SB_SOURCE
190
+ # define STATMOUNT_SB_SOURCE 0x00000200U
191
+ # endif
192
+ # ifndef LSMT_ROOT
193
+ # define LSMT_ROOT UINT64_MAX
194
+ # endif
195
+ #endif
196
+
197
+ #endif
@@ -0,0 +1,53 @@
1
+ /* Generated by tools/generate_constants.rb from Linux UAPI headers. */
2
+ #include "ruby.h"
3
+
4
+ void mountfd_define_constants(VALUE native)
5
+ {
6
+ #define DEF(name, value) rb_define_const(native, name, ULL2NUM(value))
7
+ DEF("FSOPEN_CLOEXEC", 1ULL);
8
+ DEF("FSPICK_CLOEXEC", 1ULL);
9
+ DEF("FSPICK_SYMLINK_NOFOLLOW", 2ULL);
10
+ DEF("FSPICK_NO_AUTOMOUNT", 4ULL);
11
+ DEF("FSPICK_EMPTY_PATH", 8ULL);
12
+ DEF("FSCONFIG_SET_FLAG", 0ULL);
13
+ DEF("FSCONFIG_SET_STRING", 1ULL);
14
+ DEF("FSCONFIG_SET_BINARY", 2ULL);
15
+ DEF("FSCONFIG_SET_PATH", 3ULL);
16
+ DEF("FSCONFIG_SET_PATH_EMPTY", 4ULL);
17
+ DEF("FSCONFIG_SET_FD", 5ULL);
18
+ DEF("FSCONFIG_CMD_CREATE", 6ULL);
19
+ DEF("FSCONFIG_CMD_RECONFIGURE", 7ULL);
20
+ DEF("FSCONFIG_CMD_CREATE_EXCL", 8ULL);
21
+ DEF("FSMOUNT_CLOEXEC", 1ULL);
22
+ DEF("OPEN_TREE_CLONE", 1ULL);
23
+ DEF("OPEN_TREE_CLOEXEC", 524288ULL);
24
+ DEF("MOVE_MOUNT_F_SYMLINKS", 1ULL);
25
+ DEF("MOVE_MOUNT_F_AUTOMOUNTS", 2ULL);
26
+ DEF("MOVE_MOUNT_F_EMPTY_PATH", 4ULL);
27
+ DEF("MOVE_MOUNT_T_SYMLINKS", 16ULL);
28
+ DEF("MOVE_MOUNT_T_AUTOMOUNTS", 32ULL);
29
+ DEF("MOVE_MOUNT_T_EMPTY_PATH", 64ULL);
30
+ DEF("MOVE_MOUNT_SET_GROUP", 256ULL);
31
+ DEF("MOVE_MOUNT_BENEATH", 512ULL);
32
+ DEF("MOUNT_ATTR_RDONLY", 1ULL);
33
+ DEF("MOUNT_ATTR_NOSUID", 2ULL);
34
+ DEF("MOUNT_ATTR_NODEV", 4ULL);
35
+ DEF("MOUNT_ATTR_NOEXEC", 8ULL);
36
+ DEF("MOUNT_ATTR__ATIME", 112ULL);
37
+ DEF("MOUNT_ATTR_RELATIME", 0ULL);
38
+ DEF("MOUNT_ATTR_NOATIME", 16ULL);
39
+ DEF("MOUNT_ATTR_STRICTATIME", 32ULL);
40
+ DEF("MOUNT_ATTR_NODIRATIME", 128ULL);
41
+ DEF("MOUNT_ATTR_IDMAP", 1048576ULL);
42
+ DEF("MOUNT_ATTR_NOSYMFOLLOW", 2097152ULL);
43
+ DEF("AT_RECURSIVE", 32768ULL);
44
+ DEF("AT_EMPTY_PATH", 4096ULL);
45
+ DEF("MS_UNBINDABLE", 131072ULL);
46
+ DEF("MS_REC", 16384ULL);
47
+ DEF("MS_PRIVATE", 262144ULL);
48
+ DEF("MS_SLAVE", 524288ULL);
49
+ DEF("MS_SHARED", 1048576ULL);
50
+ DEF("CLONE_NEWNS", 131072ULL);
51
+ DEF("CLONE_NEWUSER", 268435456ULL);
52
+ #undef DEF
53
+ }
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mkmf"
4
+
5
+ have_header("linux/mount.h")
6
+ have_header("sys/mount.h")
7
+ have_header("sys/syscall.h")
8
+ have_header("sched.h")
9
+ have_func("syscall", "unistd.h")
10
+ have_func("unshare", "sched.h")
11
+ create_header
12
+ create_makefile("mountfd/mountfd")
@@ -0,0 +1,166 @@
1
+ #include "ruby.h"
2
+ #include "mountfd.h"
3
+ #include "compat.h"
4
+
5
+ #ifdef __linux__
6
+ #include <errno.h>
7
+ #include <stdint.h>
8
+ #include <stdlib.h>
9
+ #include <string.h>
10
+ #include <sys/ioctl.h>
11
+ #include <unistd.h>
12
+
13
+ #define MOUNTFD_STAT_SIZE 512
14
+ #define MOUNTFD_STAT_MASK (STATMOUNT_SB_BASIC | STATMOUNT_MNT_BASIC | \
15
+ STATMOUNT_PROPAGATE_FROM | STATMOUNT_MNT_ROOT | STATMOUNT_MNT_POINT | \
16
+ STATMOUNT_FS_TYPE | STATMOUNT_MNT_NS_ID | STATMOUNT_MNT_OPTS | \
17
+ STATMOUNT_FS_SUBTYPE | STATMOUNT_SB_SOURCE)
18
+
19
+ struct mountfd_mnt_id_req {
20
+ uint32_t size;
21
+ uint32_t spare;
22
+ uint64_t mnt_id;
23
+ uint64_t param;
24
+ uint64_t mnt_ns_id;
25
+ };
26
+
27
+ struct mountfd_statmount {
28
+ uint32_t size;
29
+ uint32_t mnt_opts;
30
+ uint64_t mask;
31
+ uint32_t dev_major;
32
+ uint32_t dev_minor;
33
+ uint64_t sb_magic;
34
+ uint32_t sb_flags;
35
+ uint32_t fs_type;
36
+ uint64_t mnt_id;
37
+ uint64_t parent_id;
38
+ uint32_t old_id;
39
+ uint32_t old_parent_id;
40
+ uint64_t attrs;
41
+ uint64_t propagation;
42
+ uint64_t peer_group;
43
+ uint64_t master;
44
+ uint64_t propagate_from;
45
+ uint32_t root;
46
+ uint32_t point;
47
+ uint64_t namespace_id;
48
+ uint32_t fs_subtype;
49
+ uint32_t source;
50
+ unsigned char reserved[MOUNTFD_STAT_SIZE - 128];
51
+ };
52
+
53
+ static VALUE symbol(const char *name)
54
+ {
55
+ return ID2SYM(rb_intern(name));
56
+ }
57
+
58
+ static VALUE stat_string(char *buffer, size_t capacity, uint32_t offset)
59
+ {
60
+ struct mountfd_statmount *stat = (struct mountfd_statmount *)buffer;
61
+ size_t position = MOUNTFD_STAT_SIZE + offset;
62
+ size_t available;
63
+ if (position >= capacity || position >= stat->size) return Qnil;
64
+ available = stat->size < capacity ? stat->size - position : capacity - position;
65
+ return rb_str_new(buffer + position, strnlen(buffer + position, available));
66
+ }
67
+
68
+ static VALUE stat_hash(char *buffer, size_t capacity)
69
+ {
70
+ struct mountfd_statmount *stat = (struct mountfd_statmount *)buffer;
71
+ VALUE hash = rb_hash_new();
72
+ #define PUT(name, value) rb_hash_aset(hash, symbol(name), value)
73
+ PUT("mnt_id", ULL2NUM(stat->mnt_id));
74
+ PUT("parent_id", ULL2NUM(stat->parent_id));
75
+ PUT("old_id", UINT2NUM(stat->old_id));
76
+ PUT("old_parent_id", UINT2NUM(stat->old_parent_id));
77
+ PUT("dev_major", UINT2NUM(stat->dev_major));
78
+ PUT("dev_minor", UINT2NUM(stat->dev_minor));
79
+ PUT("attrs", ULL2NUM(stat->attrs));
80
+ PUT("propagation", ULL2NUM(stat->propagation));
81
+ PUT("peer_group", ULL2NUM(stat->peer_group));
82
+ PUT("master", ULL2NUM(stat->master));
83
+ PUT("propagate_from", ULL2NUM(stat->propagate_from));
84
+ PUT("mnt_root", (stat->mask & STATMOUNT_MNT_ROOT) ? stat_string(buffer, capacity, stat->root) : Qnil);
85
+ PUT("mount_point", (stat->mask & STATMOUNT_MNT_POINT) ? stat_string(buffer, capacity, stat->point) : Qnil);
86
+ PUT("fs_type", (stat->mask & STATMOUNT_FS_TYPE) ? stat_string(buffer, capacity, stat->fs_type) : Qnil);
87
+ PUT("source", (stat->mask & STATMOUNT_SB_SOURCE) ? stat_string(buffer, capacity, stat->source) : Qnil);
88
+ PUT("options", (stat->mask & STATMOUNT_MNT_OPTS) ? stat_string(buffer, capacity, stat->mnt_opts) : Qnil);
89
+ #undef PUT
90
+ return hash;
91
+ }
92
+
93
+ static VALUE stat_one(uint64_t id, uint64_t namespace_id, int namespace_selected)
94
+ {
95
+ struct mountfd_mnt_id_req request = {
96
+ namespace_selected ? MNT_ID_REQ_SIZE_VER1 : MNT_ID_REQ_SIZE_VER0,
97
+ 0, id, MOUNTFD_STAT_MASK, namespace_id
98
+ };
99
+ size_t capacity = 4096;
100
+ char *buffer = NULL;
101
+ long result;
102
+
103
+ while (capacity <= 1024 * 1024) {
104
+ buffer = realloc(buffer, capacity);
105
+ if (!buffer) rb_memerror();
106
+ memset(buffer, 0, capacity);
107
+ result = syscall(SYS_statmount, &request, buffer, capacity, 0);
108
+ if (result == 0) {
109
+ VALUE hash = stat_hash(buffer, capacity);
110
+ free(buffer);
111
+ return hash;
112
+ }
113
+ if (errno == ENOENT) { free(buffer); return Qnil; }
114
+ if (errno != EOVERFLOW) {
115
+ int error = errno;
116
+ free(buffer); errno = error; mountfd_syscall_failed("statmount");
117
+ }
118
+ capacity *= 2;
119
+ }
120
+ free(buffer);
121
+ rb_raise(rb_eRuntimeError, "statmount response exceeds 1 MiB");
122
+ }
123
+ #endif
124
+
125
+ static VALUE native_statmounts(VALUE self, VALUE namespace_fd)
126
+ {
127
+ #ifdef __linux__
128
+ uint64_t namespace_id = 0;
129
+ int namespace_selected = !NIL_P(namespace_fd);
130
+ struct mountfd_mnt_id_req request = {MNT_ID_REQ_SIZE_VER0, 0, LSMT_ROOT, 0, 0};
131
+ uint64_t ids[256];
132
+ VALUE mounts = rb_ary_new();
133
+ long count;
134
+ size_t index;
135
+
136
+ if (namespace_selected) {
137
+ if (ioctl(NUM2INT(namespace_fd), NS_GET_MNTNS_ID, &namespace_id) < 0)
138
+ mountfd_syscall_failed("NS_GET_MNTNS_ID");
139
+ request.size = MNT_ID_REQ_SIZE_VER1;
140
+ request.mnt_ns_id = namespace_id;
141
+ }
142
+
143
+ while (1) {
144
+ count = syscall(SYS_listmount, &request, ids, 256, 0);
145
+ if (count < 0) mountfd_syscall_failed("listmount");
146
+ if (count == 0) break;
147
+ for (index = 0; index < (size_t)count; index++) {
148
+ VALUE value = stat_one(ids[index], namespace_id, namespace_selected);
149
+ if (!NIL_P(value)) rb_ary_push(mounts, value);
150
+ }
151
+ request.param = ids[count - 1];
152
+ if (count < 256) break;
153
+ }
154
+ return mounts;
155
+ #else
156
+ (void)namespace_fd;
157
+ VALUE mountfd = rb_const_get(rb_cObject, rb_intern("Mountfd"));
158
+ VALUE error = rb_const_get(mountfd, rb_intern("UnsupportedError"));
159
+ rb_raise(error, "statmount is unavailable on this platform");
160
+ #endif
161
+ }
162
+
163
+ void mountfd_mount_info_init(VALUE native)
164
+ {
165
+ rb_define_singleton_method(native, "statmounts", native_statmounts, 1);
166
+ }