lxc-exporter/lib/ns.rb
2024-09-03 16:22:47 +02:00

88 lines
2 KiB
Ruby

require 'fiddle'
require 'fiddle/import'
require 'io/extra'
class NS
extend Fiddle::Importer
dlload Fiddle.dlopen( nil)
SetNS_Function = Fiddle::Function.new handler['setns'], [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT
class <<self
def setns fd, t
r = SetNS_Function.call fd.to_i, t.to_i
SystemCallError.new "setns(#{fd.to_i})", Fiddle.last_error if -1 == r
r
end
def _open_nsfd pid, type
File.open "/proc/%d/ns/%s" % [pid, type]
end
def open pid, *types, &exe
ns = new pid, *types
if block_given?
begin yield ns
ensure ns.close
end
else ns
end
end
def change pid, *types, &exe
open pid, *types do |ns|
ns.change &exe
end
end
def enter pid, keep_open: nil
new( pid).enter keep_open: keep_open
end
end
attr_reader :pid, :fds
def initialize pid, *types
@pid, @fds = pid, {}
types = Dir.children "/proc/%d/ns" % pid if types.empty? or types.include?( :any)
types.each {|t| @fds[t.to_sym] = self.class._open_nsfd pid, t }
end
def close_ios *keep_open
keep_open =
keep_open.flatten.map do |fd|
case fd
when Integer then fd
when IO then fd.to_i
when nil # ignore
else raise ArgumentError, "Unknown file descriptor for keeping opened: #{fd.inspect}"
end
end.sort
IO.fdwalk(0) {|fd| fd.close unless keep_open.include? fd.to_i }
end
def enter keep_open: nil
close_ios keep_open, @fds.values
@fds.each {|_, fd| self.class.setns fd, 0 }
close
nil
end
def close
@fds.each {|_, fd| fd.close }
end
def change &block
if block_given?
@owns = @fds.map {|ns, _f| self.class._open_nsfd $$, ns }
begin
@fds.each {|type, fd| self.class.setns fd, 0 }
yield
ensure
@owns.each {|fd| self.class.setns fd, 0 }
end
else
@fds.each {|type, fd| self.class.setns fd, 0 }
nil
end
end
end