[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Bug in Ruby's PTY extension

ronald braswell

8/5/2007 5:29:00 PM

I'm new to the ML so please forgive me if this has been discussed
previously.

Ruby version: 1.8.5
OS: Solaris 10 x64 (11/06)
CPU: Dual core Opteron

When using expect or RExpect I was getting an intermittent premature
EOFError on the first call to expect. Catching this exception and then
going on was an ugly work around.

pty.c:

I noticed that Solaris 10 does not support TIOCSCTTY so in function
establishShell() the child process closes the slave device and reopens it to
force it to be the controlling tty. The parent process also closes the
slave device because it does not need it. I added a call to nanosleep for
20 milliseconds just before the parent process closes the slave fd at the
end of establishShell() and I now both expect and RExpect work reliably. I
suspect that just keeping a reference to the open file object in the parent
process while the child process closes and reopens the slave device prevents
the EOF from occurring -- but I am far from an expert on Solaris internals.
This may not be the best way to solve the problem and just adding the small
delay does not ensure that the problem will never happen again but so far,
so good.

Ron

_________________________________________________________________
Puzzles, trivia teasers, word scrambles and more. Play for your chance to
win! http://club.live.com/home.aspx?icid=CLUB_hotma...


2 Answers

Nobuyoshi Nakada

8/6/2007 8:38:00 AM

0

Hi,

At Mon, 6 Aug 2007 02:28:38 +0900,
ronald braswell wrote in [ruby-talk:263410]:
> I noticed that Solaris 10 does not support TIOCSCTTY so in function
> establishShell() the child process closes the slave device and reopens it to
> force it to be the controlling tty. The parent process also closes the
> slave device because it does not need it. I added a call to nanosleep for
> 20 milliseconds just before the parent process closes the slave fd at the
> end of establishShell() and I now both expect and RExpect work reliably. I
> suspect that just keeping a reference to the open file object in the parent
> process while the child process closes and reopens the slave device prevents
> the EOF from occurring -- but I am far from an expert on Solaris internals.
> This may not be the best way to solve the problem and just adding the small
> delay does not ensure that the problem will never happen again but so far,
> so good.

Does this patch work?


Index: ext/pty/expect_sample.rb
===================================================================
--- ext/pty/expect_sample.rb (revision 12878)
+++ ext/pty/expect_sample.rb (working copy)
@@ -16,8 +16,4 @@ PTY.spawn("ftp ftp.ruby-lang.org") do |r
$expect_verbose = false

- r_f.expect(/^Name.*: /) do
- w_f.print "ftp\n"
- end
-
if !ENV['USER'].nil?
username = ENV['USER']
@@ -28,9 +24,6 @@ PTY.spawn("ftp ftp.ruby-lang.org") do |r
end

- r_f.expect('word:') do
- w_f.print username+"@\n"
- end
- r_f.expect("> ") do
- w_f.print "cd pub/ruby\n"
+ r_f.expect(/^(Name).*: |(word):|> /) do
+ w_f.puts($1 ? "ftp" : $2 ? "#{username}@" : "cd pub/ruby")
end
r_f.expect("> ") do
Index: ext/pty/pty.c
===================================================================
--- ext/pty/pty.c (revision 12878)
+++ ext/pty/pty.c (working copy)
@@ -40,8 +40,8 @@
#if !defined(HAVE_OPENPTY)
#if defined(__hpux)
-static
-char *MasterDevice = "/dev/ptym/pty%s",
- *SlaveDevice = "/dev/pty/tty%s",
- *deviceNo[] = {
+static const
+char MasterDevice[] = "/dev/ptym/pty%s",
+ SlaveDevice[] = "/dev/pty/tty%s",
+ *const deviceNo[] = {
"p0","p1","p2","p3","p4","p5","p6","p7",
"p8","p9","pa","pb","pc","pd","pe","pf",
@@ -63,8 +63,8 @@ char *MasterDevice = "/dev/ptym/pty%s",
};
#elif defined(_IBMESA) /* AIX/ESA */
-static
-char *MasterDevice = "/dev/ptyp%s",
- *SlaveDevice = "/dev/ttyp%s",
- *deviceNo[] = {
+static const
+char MasterDevice[] = "/dev/ptyp%s",
+ SlaveDevice[] = "/dev/ttyp%s",
+ *const deviceNo[] = {
"00","01","02","03","04","05","06","07","08","09","0a","0b","0c","0d","0e","0f",
"10","11","12","13","14","15","16","17","18","19","1a","1b","1c","1d","1e","1f",
@@ -85,8 +85,8 @@ char *MasterDevice = "/dev/ptyp%s",
};
#elif !defined(HAVE_PTSNAME)
-static
-char *MasterDevice = "/dev/pty%s",
- *SlaveDevice = "/dev/tty%s",
- *deviceNo[] = {
+static const
+char MasterDevice[] = "/dev/pty%s",
+ SlaveDevice[] = "/dev/tty%s",
+ *const deviceNo[] = {
"p0","p1","p2","p3","p4","p5","p6","p7",
"p8","p9","pa","pb","pc","pd","pe","pf",
@@ -102,6 +102,4 @@ char *MasterDevice = "/dev/pty%s",
#endif /* !defined(HAVE_OPENPTY) */

-static char SlaveName[DEVICELEN];
-
#ifndef HAVE_SETEUID
# ifdef HAVE_SETREUID
@@ -156,15 +154,13 @@ pty_syswait(info)
if (cpid == -1) return Qnil;

-#if defined(IF_STOPPED)
- if (IF_STOPPED(status)) { /* suspend */
- raise_from_wait("stopped", info);
- }
-#elif defined(WIFSTOPPED)
- if (WIFSTOPPED(status)) { /* suspend */
- raise_from_wait("stopped", info);
- }
+#if defined(WIFSTOPPED)
+#elif defined(IF_STOPPED)
+#define WIFSTOPPED(status) IF_STOPPED(status)
#else
---->> Either IF_STOPPED or WIFSTOPPED is needed <<----
#endif /* WIFSTOPPED | IF_STOPPED */
+ if (WIFSTOPPED(status)) { /* suspend */
+ raise_from_wait("stopped", info);
+ }
else if (kill(info->child_pid, 0) == 0) {
raise_from_wait("changed", info);
@@ -177,5 +173,5 @@ pty_syswait(info)
}

-static void getDevice _((int*, int*));
+static void getDevice _((int*, int*, char [DEVICELEN]));

struct exec_info {
@@ -195,11 +191,12 @@ pty_exec(v)

static void
-establishShell(argc, argv, info)
+establishShell(argc, argv, info, SlaveName)
int argc;
VALUE *argv;
struct pty_info *info;
+ char SlaveName[DEVICELEN];
{
int i,master,slave;
- char *p,*getenv();
+ char *p, tmp, *getenv();
struct passwd *pwent;
VALUE v;
@@ -224,5 +221,5 @@ establishShell(argc, argv, info)
argv = &v;
}
- getDevice(&master,&slave);
+ getDevice(&master, &slave, SlaveName);

info->thread = rb_thread_current();
@@ -274,4 +271,5 @@ establishShell(argc, argv, info)
close(master);
#endif
+ write(slave, "", 1);
dup2(slave,0);
dup2(slave,1);
@@ -289,4 +287,5 @@ establishShell(argc, argv, info)
}

+ read(master, &tmp, 1);
close(slave);

@@ -306,6 +305,7 @@ pty_finalize_syswait(info)

static int
-get_device_once(master, slave, fail)
+get_device_once(master, slave, SlaveName, fail)
int *master, *slave, fail;
+ char SlaveName[DEVICELEN];
{
#if defined HAVE_OPENPTY
@@ -354,4 +354,5 @@ get_device_once(master, slave, fail)
if(ioctl(j, I_PUSH, "ptem") != -1) {
if(ioctl(j, I_PUSH, "ldterm") != -1) {
+ ioctl(j, I_PUSH, "ttcompat");
#endif
*master = i;
@@ -396,10 +397,11 @@ get_device_once(master, slave, fail)

static void
-getDevice(master, slave)
+getDevice(master, slave, SlaveName)
int *master, *slave;
+ char SlaveName[DEVICELEN];
{
- if (get_device_once(master, slave, 0)) {
+ if (get_device_once(master, slave, SlaveName, 0)) {
rb_gc();
- get_device_once(master, slave, 1);
+ get_device_once(master, slave, SlaveName, 1);
}
}
@@ -418,9 +420,10 @@ pty_getpty(argc, argv, self)
VALUE rport = rb_obj_alloc(rb_cFile);
VALUE wport = rb_obj_alloc(rb_cFile);
+ char SlaveName[DEVICELEN];

MakeOpenFile(rport, rfptr);
MakeOpenFile(wport, wfptr);

- establishShell(argc, argv, &info);
+ establishShell(argc, argv, &info, SlaveName);

rfptr->mode = rb_io_mode_flags("r");


--
Nobu Nakada

Daniel Berger

8/6/2007 2:19:00 PM

0



On Aug 5, 11:28 am, "ronald braswell" <rpbrasw...@hotmail.com> wrote:
> I'm new to the ML so please forgive me if this has been discussed
> previously.
>
> Ruby version: 1.8.5
> OS: Solaris 10 x64 (11/06)
> CPU: Dual core Opteron
>
> When using expect or RExpect I was getting an intermittent premature
> EOFError on the first call to expect. Catching this exception and then
> going on was an ugly work around.
>
> pty.c:
>
> I noticed that Solaris 10 does not support TIOCSCTTY so in function
> establishShell() the child process closes the slave device and reopens it to
> force it to be the controlling tty. The parent process also closes the
> slave device because it does not need it. I added a call to nanosleep for
> 20 milliseconds just before the parent process closes the slave fd at the
> end of establishShell() and I now both expect and RExpect work reliably. I
> suspect that just keeping a reference to the open file object in the parent
> process while the child process closes and reopens the slave device prevents
> the EOF from occurring -- but I am far from an expert on Solaris internals.
> This may not be the best way to solve the problem and just adding the small
> delay does not ensure that the problem will never happen again but so far,
> so good.

This quote from comp.programming may be useful:

"In System V, the controlling terminal is the first tty that's opened
that is not already associated with a session. If you don't want that
tty to be the controlling terminal, use the O_NOCTTY flag on open().

You don't need the TIOCSCTTY ioctl in SVR4 systems."

http://tinyurl....

Regards,

Dan