Module: Mountfd
- Defined in:
- lib/mountfd.rb,
lib/mountfd/core.rb,
lib/mountfd/version.rb,
lib/mountfd/namespace.rb,
lib/mountfd/attributes.rb,
lib/mountfd/mount_info.rb,
lib/mountfd/user_namespace.rb,
sig/mountfd.rbs,
ext/mountfd/mountfd.c
Defined Under Namespace
Modules: Attributes, MountInfoParser, Namespace, Native, _Fileno
Classes: AttachedMount, ConfigError, DetachedMount, Diagnostic, Error, FsContext, IdmapError, MountError, MountInfo, UnsupportedError, UserNamespace
Constant Summary
collapse
- AT_FDCWD =
-100
- VERSION =
"0.1.0"
Class Method Summary
collapse
-
.bind(source, target, recursive: false, attrs: {}, idmap: nil) ⇒ AttachedMount
-
.features ⇒ Array[Symbol]
-
.fileno(value) ⇒ Object
-
.mount(source, target, type: source, options: {}, attrs: {}) ⇒ AttachedMount
-
.mount_at(path, **options) ⇒ MountInfo?
-
.mounts(ns: nil, backend: nil) ⇒ Array[MountInfo]
-
.mounts_backend ⇒ :statmount, :mountinfo
-
.open_tree(path, recursive: false) ⇒ Object
-
.pending_mounts ⇒ Array[DetachedMount]
-
.pivot_root(new_root, put_old) ⇒ nil
-
.replace(path) { ... } ⇒ AttachedMount
-
.set_attributes(path, attrs: {}, propagation: nil, recursive: false) ⇒ nil
-
.supported? ⇒ Boolean
-
.umount(path, detach: true, force: false) ⇒ nil
Class Method Details
.bind(source, target, recursive: false, attrs: {}, idmap: nil) ⇒ AttachedMount
252
253
254
255
256
257
258
259
260
261
262
263
|
# File 'lib/mountfd/core.rb', line 252
def bind(source, target, recursive: false, attrs: {}, idmap: nil)
namespace = UserNamespace.create(**idmap) if idmap.is_a?(Hash)
detached = open_tree(source, recursive: recursive)
apply_attributes(detached, attrs, recursive: recursive)
detached.idmap!(namespace || idmap) if idmap
detached.attach(target)
rescue StandardError
detached&.discard unless detached&.closed?
raise
ensure
namespace&.close unless namespace&.closed?
end
|
.features ⇒ Array[Symbol]
176
177
178
179
180
181
182
183
184
185
|
# File 'lib/mountfd/core.rb', line 176
def features
return [] unless supported?
values = [:new_mount_api]
values.concat([:mount_setattr, :idmap]) if Native.syscall_available?("mount_setattr")
values << :statmount if %w[statmount listmount].all? { Native.syscall_available?(_1) }
values << :move_mount_beneath if kernel_at_least?(6, 5)
values << :create_excl if kernel_at_least?(6, 6)
values
end
|
.fileno(value) ⇒ Object
296
|
# File 'lib/mountfd/core.rb', line 296
def fileno(value) = value.respond_to?(:fileno) ? value.fileno : Integer(value)
|
.mount(source, target, type: source, options: {}, attrs: {}) ⇒ AttachedMount
238
239
240
241
242
243
244
245
246
247
248
249
250
|
# File 'lib/mountfd/core.rb', line 238
def mount(source, target, type: source, options: {}, attrs: {})
detached = nil
FsContext.open(type) do |context|
context.set("source", source) unless source.to_s == type.to_s
options.each { |key, value| context.set(key, value) }
context.create!
detached = context.mount(attrs: attrs)
detached.attach(target)
end
rescue StandardError
detached&.discard unless detached&.closed?
raise
end
|
.mount_at(path, **options) ⇒ MountInfo?
220
221
222
223
|
# File 'lib/mountfd/core.rb', line 220
def mount_at(path, **options)
target = File.expand_path(File.path(path))
mounts(**options).find { File.expand_path(_1.mount_point) == target }
end
|
.mounts(ns: nil, backend: nil) ⇒ Array[MountInfo]
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
|
# File 'lib/mountfd/core.rb', line 189
def mounts(ns: nil, backend: nil)
selected = backend || preferred_mounts_backend(ns)
if selected == :statmount
@mounts_backend = :statmount
values = if ns.nil?
Native.statmounts(nil)
elsif ns.respond_to?(:fileno)
Native.statmounts(fileno(ns))
else
File.open("/proc/#{Integer(ns)}/ns/mnt") { Native.statmounts(_1.fileno) }
end
return values.map { mount_info_from_statmount(_1) }
end
raise ArgumentError, "backend must be :statmount or :mountinfo" unless selected == :mountinfo
if ns&.respond_to?(:fileno)
raise UnsupportedError, "mount namespace descriptors require statmount on Linux 6.11 or newer"
end
@mounts_backend = :mountinfo
pid = ns.nil? ? "self" : Integer(ns)
read_mountinfo(pid)
rescue SystemCallError, UnsupportedError
raise if backend == :statmount || ns&.respond_to?(:fileno)
@mounts_backend = :mountinfo
read_mountinfo(ns ? Integer(ns) : "self")
end
|
.mounts_backend ⇒ :statmount, :mountinfo
218
|
# File 'lib/mountfd/core.rb', line 218
def mounts_backend = @mounts_backend || preferred_mounts_backend(nil)
|
.open_tree ⇒ void
.open_tree(path, recursive:) ⇒ DetachedMount
225
226
227
228
229
230
231
232
233
234
235
236
|
# File 'lib/mountfd/core.rb', line 225
def open_tree(path, recursive: false)
flags = Native::OPEN_TREE_CLONE | Native::OPEN_TREE_CLOEXEC
flags |= Native::AT_RECURSIVE if recursive
mount = DetachedMount.new(Native.open_tree(AT_FDCWD, File.path(path), flags))
return mount unless block_given?
begin
yield mount
ensure
mount.discard unless mount.closed?
end
end
|
187
|
# File 'lib/mountfd/core.rb', line 187
def pending_mounts = (@pending_mounts || []).reject(&:closed?).dup
|
.pivot_root(new_root, put_old) ⇒ nil
270
|
# File 'lib/mountfd/core.rb', line 270
def pivot_root(new_root, put_old) = Native.pivot_root(File.path(new_root), File.path(put_old))
|
283
284
285
286
287
288
289
290
291
292
293
294
|
# File 'lib/mountfd/core.rb', line 283
def replace(path)
target = File.path(path)
detached = yield
raise ArgumentError, "replace block must return a DetachedMount" unless detached.is_a?(DetachedMount)
detached.attach(target, beneath: true)
umount(target)
AttachedMount.new(target)
rescue StandardError
detached&.discard unless detached&.closed?
raise
end
|
.set_attributes(path, attrs: {}, propagation: nil, recursive: false) ⇒ nil
272
273
274
275
276
277
278
279
280
281
|
# File 'lib/mountfd/core.rb', line 272
def set_attributes(path, attrs: {}, propagation: nil, recursive: false)
set, clr = Attributes.build(attrs)
flags = recursive ? Native::AT_RECURSIVE : 0
Native.mount_setattr(
AT_FDCWD, File.path(path), flags, set, clr, Attributes.propagation(propagation), nil
)
nil
rescue SystemCallError => error
raise MountError, "mount_setattr: #{error.message}", cause: error
end
|
.umount(path, detach: true, force: false) ⇒ nil
265
266
267
268
|
# File 'lib/mountfd/core.rb', line 265
def umount(path, detach: true, force: false)
flags = (detach ? 2 : 0) | (force ? 1 : 0)
Native.umount2(File.path(path), flags)
end
|