Pty & signals with wrapped shell

hello,

for fun, i am trying to use PTY to wrap my shell. i adapted script.rb
from ext/pty and can run and exit my shell okay, but i’m having trouble
getting the signals to work correctly. i can start up the shell, run
ps and vi, and do some basic shell comands, but i can’t interrupt or
suspend any jobs started by the shell.

when i call PTY.spawn, it gives me the pid of my shell. i put a trap
call in my ruby code to grab sigint and sigstop and send those onto the
shell’s pid, but i’m pretty sure i need to send those signals to
whatever subprocess my shell is currently running.

i’ve already written a class that parses ps output and lets me query the
process stack, but it’s pretty heavy and i’d rather not use it unless i
have to. i’m hoping that there is a cleaner way to do this in pure
ruby, parsing ps or /proc feels like i’m using too much brute force. i
like how short the current code is, so is there a ruby way to route the
signal properly?

if you’re wondering why i’m doing this, i thought it would be fun to
create a ruby program that runs a shell and lets you filter the input
and output of the shell with ruby plugins. when you hit enter after
entering a command on the prompt, your command is compared and if it
matches any plugins, they are ran instead of the command being passed to
the shell. i don’t know if it’s possible but it sounded like it would
be fun to experiment with…

thank you,

doug

p.s. i’m running ruby-1.8.0-preview2 compiled on os x 10.2.

#!/usr/bin/env ruby

require ‘pty’

input, output, pid = nil, nil, nil
shell = ENV[‘SHELL’]
if shell =~ /[^\w/.]/ || !File.stat(shell).executable?
raise "ENV[SHELL] must be a valid shell path!"
exit 1 # never reached
end

sending the signal to the shell doesn’t do it, i need to send the

signal to the process the shell is currently running. not sure

how to do that…

%w/INT STOP/.each do |signal|
trap(signal) do
if pid

kill(signal, pid)

end

end
end

begin
system "stty -echo raw lnext ^_"
input, output, pid = PTY.spawn(shell)
puts "input, output, pid = #{input}, #{output}, #{pid}"
Thread.new do
while true
output.print STDIN.getc.chr
output.flush
end
end

begin
while true
c = input.sysread(512)
break if c.nil?
print c
STDOUT.flush
end
rescue
end
rescue
STDERR.puts "general pty exception: #{$!}"
ensure

sometimes first stty call fails, don’t know why…

system(“stty echo -raw lnext ^v”) || system(“stty -raw”)
input.close
output.close
Process.kill(0, pid) && Process.kill(9, pid)
end

···


“Contrary to what most people say, the most dangerous animal in the
world is not the lion or the tiger or even the elephant. It’s a shark
riding on an elephant’s back, just trampling and eating everything they
see.” – Jack Handey

i’ve already written a class that parses ps output and lets me query the
process stack, but it’s pretty heavy and i’d rather not use it unless i
have to. i’m hoping that there is a cleaner way to do this in pure
ruby, parsing ps or /proc feels like i’m using too much brute force. i
like how short the current code is, so is there a ruby way to route the
signal properly?

As far as that goes, Daniel Berger has written a module for this,
sys-proc or some such, searching on RAA should find it.

···


Eric Hodel - drbrain@segment7.net - http://segment7.net
All messages signed with fingerprint:
FEC2 57F1 D465 EB15 5D6E 7C11 332A 551C 796C 9F04

Doug Beaver doug@beaver.net wrote in message news:20030306222419.A84092@beaver.net

hello,

[ cut ]

input, output, pid = PTY.spawn(shell)
puts “input, output, pid = #{input}, #{output}, #{pid}”
Thread.new do
while true
output.print STDIN.getc.chr
output.flush
end
end

In a recent thread on pty matz asserted that you must do:
PTY.spawn(shell) do |input, output, pid|

rest of handling here

end

I don’t know if this helps you with your problem or not.
I find that I also must wrap in ‘PTY.protect_signal do … end’ or
I get the dreaded ‘child_changed’ exception, but maybe that’s not
necessary for your application.

Cheers,

Han Holl