2024-01-20 23:22:16 +01:00
|
|
|
require 'fiddle'
|
|
|
|
require 'fiddle/import'
|
2024-09-03 16:22:47 +02:00
|
|
|
require 'io/extra'
|
2024-01-20 23:22:16 +01:00
|
|
|
|
|
|
|
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
|
2024-09-03 16:22:47 +02:00
|
|
|
|
|
|
|
def enter pid, keep_open: nil
|
|
|
|
new( pid).enter keep_open: keep_open
|
|
|
|
end
|
2024-01-20 23:22:16 +01:00
|
|
|
end
|
|
|
|
|
2024-09-03 16:22:47 +02:00
|
|
|
attr_reader :pid, :fds
|
2024-01-20 23:22:16 +01:00
|
|
|
|
|
|
|
def initialize pid, *types
|
|
|
|
@pid, @fds = pid, {}
|
2024-09-03 16:22:47 +02:00
|
|
|
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
|
2024-01-20 23:22:16 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def close
|
2024-09-03 16:22:47 +02:00
|
|
|
@fds.each {|_, fd| fd.close }
|
2024-01-20 23:22:16 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def change &block
|
2024-09-03 16:22:47 +02:00
|
|
|
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
|
2024-01-20 23:22:16 +01:00
|
|
|
@fds.each {|type, fd| self.class.setns fd, 0 }
|
2024-09-03 16:22:47 +02:00
|
|
|
nil
|
2024-01-20 23:22:16 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|