Skip to content

Commit

Permalink
Add a PTY module sample. Its not exactly a full implementation yet.
Browse files Browse the repository at this point in the history
git-svn-id: http://svn.codehaus.org/jruby/trunk/jruby@7604 961051c9-f516-0410-bf72-c9f7e237a7b7
  • Loading branch information
vp-of-awesome committed Aug 31, 2008
1 parent 1593cdb commit cb4dfa5
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 0 deletions.
4 changes: 4 additions & 0 deletions lib/ruby/site_ruby/1.8/ffi/ffi.rb
Expand Up @@ -181,6 +181,9 @@ def self.find_type(name)
4 => :int,
8 => :long_long,
}
def self.type_size(t)
JRuby::FFI.type_size(t)
end
end

module JRuby::FFI
Expand Down Expand Up @@ -289,6 +292,7 @@ class Config
NativeType::FLOAT64 => 8,
NativeType::LONG => JRuby::FFI::Platform::LONG_SIZE / 8,
NativeType::ULONG => JRuby::FFI::Platform::LONG_SIZE / 8,
NativeType::POINTER => JRuby::FFI::Platform::ADDRESS_SIZE / 8,
}

def self.size_to_type(size)
Expand Down
5 changes: 5 additions & 0 deletions lib/ruby/site_ruby/1.8/ffi/memorypointer.rb
Expand Up @@ -40,6 +40,11 @@ def self.new(type, count=nil, clear=true)
ptr
end
end
def self.from_string(s)
ptr = self.new(s.length + 1, 1, false)
ptr.put_string(0, s)
ptr
end
# Indicates how many bytes the type that the pointer is cast as uses.
attr_accessor :type_size

Expand Down
109 changes: 109 additions & 0 deletions samples/ffi/pty.rb
@@ -0,0 +1,109 @@
require 'ffi'


module PTY
private
module LibC
extend JRuby::FFI::Library
attach_function :forkpty, [ :buffer_out, :buffer_out, :buffer_in, :buffer_in ], :pid_t
attach_function :openpty, [ :buffer_out, :buffer_out, :buffer_out, :buffer_in, :buffer_in ], :int
attach_function :login_tty, [ :int ], :int
attach_function :close, [ :int ], :int
attach_function :strerror, [ :int ], :string
attach_function :fork, [], :pid_t
attach_function :execv, [ :string, :buffer_in ], :int
attach_function :execvp, [ :string, :buffer_in ], :int
attach_function :dup2, [ :int, :int ], :int
end
Buffer = JRuby::FFI::Buffer
def self.build_args(args)
cmd = args.shift
cmd_args = args.map do |arg|
MemoryPointer.from_string(arg)
end
exec_args = MemoryPointer.new(:pointer, 1 + cmd_args.length + 1)
exec_cmd = MemoryPointer.from_string(cmd)
exec_args[0].put_pointer(0, exec_cmd)
cmd_args.each_with_index do |arg, i|
exec_args[i + 1].put_pointer(0, arg)
end
[ cmd, exec_args ]
end
public
def self.getpty(*args, &block)
mfdp = Buffer.new :int
name = Buffer.new 1024
#
# All the execv setup is done in the parent, since doing anything other than
# execv in the child after fork is really flakey
#
exec_cmd, exec_args = build_args(args)
pid = LibC.forkpty(mfdp, name, nil, nil)
raise "forkpty failed: #{LibC.strerror(FFI.errno)}" if pid < 0
if pid == 0
LibC.execvp(exec_cmd, exec_args)
exit 1
end
masterfd = mfdp.get_int(0)
if block_given?
yield masterfd, masterfd, pid
LibC.close(masterfd)
else
[ masterfd, masterfd, pid ]
end
end
def self.getpty2(*args, &block)
mfdp = Buffer.alloc_out :int
sfdp = Buffer.alloc_out :int
name = Buffer.alloc_out 1024
#
# All the execv setup is done in the parent, since doing anything other than
# execv in the child after fork is really flakey
#
exec_cmd, exec_args = build_args(args)
retval = LibC.openpty(mfdp, sfdp, name, nil, nil)
raise "openpty failed: #{LibC.strerror(FFI.errno)}" unless retval == 0
pid = LibC.fork()
if pid < 0
error = FFI.errno
LibC.close(mfdp.get_int(0))
LibC.close(sfdp.get_int(0))
raise "fork failed: #{LibC.strerror(error)}"
end
if pid == 0
LibC.close(mfdp.get_int(0))
# Make the slave fd the new stdin/out/err
fd = sfdp.get_int(0)
LibC.dup2(fd, 0)
LibC.dup2(fd, 1)
LibC.dup2(fd, 2)
LibC.close(fd)
LibC.login_tty(0)
LibC.execvp(exec_cmd, exec_args)
exit 1
end
slavefd = sfdp.get_int(0)
LibC.close(slavefd) # not needed in the parent
masterfd = mfdp.get_int(0)
if block_given?
yield masterfd, masterfd, pid
LibC.close(masterfd)
else
[ masterfd, masterfd, pid ]
end
end


end
module LibC
extend JRuby::FFI::Library
attach_function :close, [ :int ], :int
attach_function :write, [ :int, :buffer_in, :size_t ], :ssize_t
attach_function :read, [ :int, :buffer_out, :size_t ], :ssize_t
end
PTY.getpty("/bin/ls", "-alR", "/") { |rfd, wfd, pid|
puts "child pid=#{pid}"
while LibC.read(rfd, buf = 0.chr * 256, 256) > 0
puts "Received from child='#{buf.strip}'"
end
}

0 comments on commit cb4dfa5

Please sign in to comment.