Forum: Ruby Strange problem with PTY.spawn()

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
98997c6ddfa98d33272d17a7de6e9749?d=identicon&s=25 Reto Schuettel (Guest)
on 2006-04-10 17:07
(Received via mailing list)
Hi

I've some troubles using PTY on a Solais 8 System:

| $ ruby1.8 -rpty  -e 'PTY.spawn("/bin/telnet testsite1");  '
| -e:1:in `spawn': can't get Master/Slave device (RuntimeError)
|         from -e:1

The system:
| $ uname -a
| SunOS hostname 5.8 Generic_108528-29 sun4u sparc SUNW,Sun-Fire-280R

Ruby:
| $ ruby1.8 -v
| ruby 1.8.4 (2005-12-24) [sparc-solaris2.8]

Everything works as it should with a old version of ruby:
| $ ruby -v
| ruby 1.6.8 (2002-12-24) [sparc-solaris2.8]

I've attached the output of truss. Please let me know if more
information is needed.

Can anybody help me with this? I have no idea how I could fix/avoid this
problem.

Cheers,
Reto Schuettel
98997c6ddfa98d33272d17a7de6e9749?d=identicon&s=25 Reto Schuettel (Guest)
on 2006-04-10 17:26
(Received via mailing list)
On Tue, Apr 11, 2006 at 12:06:56AM +0900, Reto Schuettel wrote:
> I've attached the output of truss. Please let me know if more
> information is needed.

*grmbl* and here it is ... :/ (I hope the ML doesn't reject mails with
attachements).
98997c6ddfa98d33272d17a7de6e9749?d=identicon&s=25 Reto Schuettel (Guest)
on 2006-04-10 23:37
(Received via mailing list)
Hi,

it's me again :) (one more mail and you can call it spamming, ;))[1]

On Tue, Apr 11, 2006 at 12:06:56AM +0900, Reto Schuettel wrote:
> Can anybody help me with this? I have no idea how I could fix/avoid this
> problem.

Let me ask another question. Why should I (or RExpect, to be precise)
use PTY at all? As far as I can see it only spawns a programm and gets
stdin/stdout. Couldn't I use open3/open4 for the same purpose? I've
modified/extended the RExpect a little bit, so I'm alread used to the
internals, from my point of view I can't see any differences to the Open
libraries.

I have to talk network devices (Cisco Router/Switches) over ssh/telnet
session (ssh prefered, of course ;)).


Cheers,
Reto Schuettel


[1] http://www.youtube.com/watch?v=XZ6N5m8FpVg
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-04-10 23:56
(Received via mailing list)
On Tue, 11 Apr 2006, Reto Schuettel wrote:

> stdin/stdout. Couldn't I use open3/open4 for the same purpose? I've
> modified/extended the RExpect a little bit, so I'm alread used to the
> internals, from my point of view I can't see any differences to the Open
> libraries.
>
> I have to talk network devices (Cisco Router/Switches) over ssh/telnet
> session (ssh prefered, of course ;)).
>
>
> Cheers,
> Reto Schuettel

some programs require a tty and some do not.  and example of something
that
requires a tty is ssh when it asks for you password since it needs to
hide the
typed chars.  you can't do that with a pure io stream.  do, depending on
which
program you are driving you may or may not be able to use open3.  you
may want
to check out my session package, it wraps open3 in a way that makes it
brain
dead simple to use with sh.

regards.

-a
8cfdf47d27893fbd55d6b9565c34fbe4?d=identicon&s=25 Bruce Woodward (Guest)
on 2006-04-11 00:14
(Received via mailing list)
Reto,

Looking at ruby-1.8.4/ext/pty/pty.c, line 351. To get the runtime error
"can't get Master/Slave device" the opening on /dev/ptmx is failing.
Do you have the file /dev/ptmx?
On a Solaris 8 system here I have;

# uname -a
SunOS camsapc 5.8 Generic_117350-18 sun4u sparc
SUNW,Ultra-Enterprise-10000
# ls -l /dev/ptmx
lrwxrwxrwx   1 root     root          30 Apr 16  2005 /dev/ptmx ->
../devices/pseudo/clone@0:ptmx
# ls -lL /dev/ptmx
crw-rw-rw-   1 root     sys       11, 23 Feb 19  2002 /dev/ptmx


good luck.

Bruce.
98997c6ddfa98d33272d17a7de6e9749?d=identicon&s=25 Reto Schuettel (Guest)
on 2006-04-11 07:14
(Received via mailing list)
Hi Bruce

On Tue, Apr 11, 2006 at 07:12:54AM +0900, Bruce Woodward wrote:
> Reto,
>
> Looking at ruby-1.8.4/ext/pty/pty.c, line 351. To get the runtime error
> "can't get Master/Slave device" the opening on /dev/ptmx is failing.
> Do you have the file /dev/ptmx?
> On a Solaris 8 system here I have;

Nono.. the open was fine (look at the truss output, it returns 3). All
the
commands in this big if-block have to be successfull, otherwise the
error message will be shown.

> # ls -l /dev/ptmx
> lrwxrwxrwx   1 root     root          30 Apr 16  2005 /dev/ptmx -> > 
../devices/pseudo/clone@0:ptmx
> # ls -lL /dev/ptmx > crw-rw-rw-   1 root     sys       11, 23 Feb 19  2002 /dev/ptmx
>

Same here ...

>
> good luck.

luck... I hope this problem doesn't depend on my luck :) .. but thanks
anyway.


Cheers,
Reto
Schüttel
F1d6cc2b735bfd82c8773172da2aeab9?d=identicon&s=25 unknown (Guest)
on 2006-04-11 15:53
(Received via mailing list)
Hi,

At Tue, 11 Apr 2006 00:22:42 +0900,
Reto Schuettel wrote in [ruby-talk:188393]:
> > I've attached the output of truss. Please let me know if more
> > information is needed.
>
> *grmbl* and here it is ... :/ (I hope the ML doesn't reject mails with
> attachements).

Seems grantpt() failed.  Can't you try with this patch?


Index: ext/pty/pty.c
===================================================================
RCS file: /cvs/ruby/src/ruby/ext/pty/pty.c,v
retrieving revision 1.19.2.3
diff -p -U2 -r1.19.2.3 pty.c
--- ext/pty/pty.c	8 Sep 2005 05:59:40 -0000	1.19.2.3
+++ ext/pty/pty.c	11 Apr 2006 13:51:09 -0000
@@ -350,4 +350,5 @@ getDevice(master,slave)

     if((i = open("/dev/ptmx", O_RDWR, 0)) != -1) {
+	int e;
 	s = signal(SIGCHLD, SIG_DFL);
 	if(grantpt(i) != -1) {
@@ -372,7 +373,9 @@ getDevice(master,slave)
 	    }
 	}
+	e = errno;
 	close(i);
+	errno = e;
     }
-    rb_raise(rb_eRuntimeError, "can't get Master/Slave device");
+    rb_sys_fail("can't get Master/Slave device");
 #else
     char **p;
98997c6ddfa98d33272d17a7de6e9749?d=identicon&s=25 Reto Schuettel (Guest)
on 2006-04-18 11:17
(Received via mailing list)
Hi Nobu

Sorry for the long delay!

On Tue, Apr 11, 2006 at 10:52:03PM +0900, nobu@ruby-lang.org wrote:
> Seems grantpt() failed.  Can't you try with this patch?

I've applied the patch and rerun the test, here's output. The (new)
truss output is attached.

$ ruby1.8 -rpty  -e 'PTY.spawn("/bin/telnet")'
-e:1:in `spawn': No such file or directory - can't get Master/Slave
device (Errno::ENOENT)
        from -e:1

Please tell me if you need anything else!

Thanks,
Reto Schüttel
98997c6ddfa98d33272d17a7de6e9749?d=identicon&s=25 Reto Schuettel (Guest)
on 2006-04-20 16:43
(Received via mailing list)
Hi

On Tue, Apr 18, 2006 at 06:15:14PM +0900, Reto Schuettel wrote:
> Please tell me if you need anything else!

I've found some more stuff:

This we already know:
 | $ ruby1.8 -rpty -e   'so, si, pid = PTY.spawn("/bin/true"); '
 | -e:1:in `spawn': No such file or directory - can't get Master/Slave
device (Errno::ENOENT)
 | 	from -e:1

But what happens if we add something before the call to PTY.spawn()
 | $ ruby1.8 -rpty -e   'puts "blub"; so, si, pid =
PTY.spawn("/bin/true"); '
 | blub
 | -e:1: [BUG] rb_sys_fail(can't get Master/Slave device) - errno == 0
 | ruby 1.8.4 (2005-12-24) [sparc-solaris2.8]
 |
 | Abort

Oops? Different error? (Nobus patch is applied on this machine).

The following message in the truss log was another thing that bothered
me:
 | 26811:  execve("/usr/lib/pt_chmod", 0xFFBEE340, 0xFFBEFAC8)
 | 26811:          *** cannot trace across exec() of /usr/lib/pt_chmod
***

Eventually I tried to run the process with user rights and then truss it
with root rights:

 | $ ruby1.8 -rpty -e   'puts $$; readline; so, si, pid =
PTY.spawn("/bin/true"); '
 19467
[ here I started a second terminal and attached a truss, which is
running as root, hen I pressed enter ]

 |
 | -e:1: [BUG] rb_sys_fail(can't get Master/Slave device) - errno == 0
 |  ruby 1.8.4 (2005-12-24) [sparc-solaris2.8]
 |
 | Abort

This root-truss covers now everything and it's attached to this email as
'pty-spawn-problem.truss'.

Then I tried soemthing else, I run the whole ruby process as root:
 | $ sudo ruby1.8 -rpty -e   'puts $$; so, si, pid =
PTY.spawn("/bin/true"); '
 | 20320

Hm, this works now. So perhaps it's a permission problem. Afterwards I
tried to run a command which produces output:

 | $ sudo ruby1.8 -rpty -e   'puts $$; so, si, pid =
PTY.spawn("uptime"); puts so.read;'
 | 20351

No output. Lets try it with sysread:

 | $ sudo ruby1.8 -rpty -e   'puts $$; so, si, pid =
PTY.spawn("uptime"); puts so.sysread(1024);'
 | 20361
 | -e:1:in `sysread': end of file reached (EOFError)
 | 	from -e:1

Nothing... perhaps it has to do with the fact that uptime imediatly
quits (my
linux boxes produces sometimes an exception before I can read the
output)

 | $ sudo ruby1.8 -rpty -e   'puts $$; so, si, pid = PTY.spawn("ssh
testsite1"); puts so.sysread(1024);'
 | 20603
 | -e:1:in `sysread': end of file reached (EOFError)
 | 	from -e:1

Same here.. :/

I really don't get it.. im completly out of ideas...

Please tell me if you need anything else.

Regards,
Reto Schüttel
F1d6cc2b735bfd82c8773172da2aeab9?d=identicon&s=25 unknown (Guest)
on 2006-04-21 03:53
(Received via mailing list)
Hi,

At Thu, 20 Apr 2006 23:42:03 +0900,
Reto Schuettel wrote in [ruby-talk:189572]:
> But what happens if we add something before the call to PTY.spawn()
>  | $ ruby1.8 -rpty -e   'puts "blub"; so, si, pid = PTY.spawn("/bin/true"); '
>  | blub
>  | -e:1: [BUG] rb_sys_fail(can't get Master/Slave device) - errno == 0
>  | ruby 1.8.4 (2005-12-24) [sparc-solaris2.8]
>  |
>  | Abort
>
> Oops? Different error? (Nobus patch is applied on this machine).

Seems grantpt() on Solaris doesn't set errno perperly, or even
the return value is not correct.

Try this patch, but I don't know if it is in only particular
version of Solaris, or more.


Index: ext/pty/pty.c
===================================================================
RCS file: /cvs/ruby/src/ruby/ext/pty/pty.c,v
retrieving revision 1.19.2.3
diff -p -U2 -r1.19.2.3 pty.c
--- ext/pty/pty.c	8 Sep 2005 05:59:40 -0000	1.19.2.3
+++ ext/pty/pty.c	21 Apr 2006 01:52:56 -0000
@@ -349,9 +349,14 @@ getDevice(master,slave)
     extern int grantpt(int);

+#if defined(__solaris__) && defined(__sparc__)
+#define succeed(xxx) ((errno = 0), (xxx) != -1 && errno != 0)
+#else
+#define succeed(xxx) ((xxx) != -1)
+#endif
     if((i = open("/dev/ptmx", O_RDWR, 0)) != -1) {
 	s = signal(SIGCHLD, SIG_DFL);
-	if(grantpt(i) != -1) {
+	if(succeed(grantpt(i))) {
 	    signal(SIGCHLD, s);
-	    if(unlockpt(i) != -1) {
+	    if(succeed(unlockpt(i))) {
 		if((pn = ptsname(i)) != NULL) {
 		    if((j = open(pn, O_RDWR, 0)) != -1) {
D812408537ac3a0fa2fec96eb8811559?d=identicon&s=25 John Carter (Guest)
on 2006-04-21 04:27
(Received via mailing list)
On Tue, 11 Apr 2006, Reto Schuettel wrote:

> Let me ask another question. Why should I (or RExpect, to be precise)
> use PTY at all? As far as I can see it only spawns a programm and gets
> stdin/stdout.

One and only one (weak) reason. The pty interface permits you to drive
programs that have the implicit expectation that they are been driven
from a keyboard / screen combo and use the termios (Say "man termios"
for more info).
functions on the STDIN/STDOUT fd's.

> Couldn't I use open3/open4 for the same purpose? I've
> modified/extended the RExpect a little bit, so I'm alread used to the
> internals, from my point of view I can't see any differences to the Open
> libraries.

I did make a (very small) start on a open3 interface to RExpect. If you
feel like contributing your fixes back I would welcome them.


> I have to talk network devices (Cisco Router/Switches) over ssh/telnet
> session (ssh prefered, of course ;)).

I originally wrote rexpect to pretend to be lots and lots and lots of
imaginary devices on the end of lots and lots of imaginary rs-232 lines.

Currently my only use is to use 'ssh' to takeover my colleagues boxes
and install, configure and run distcc on them.


John Carter                             Phone : (64)(3) 358 6639
Tait Electronics                        Fax   : (64)(3) 359 4632
PO Box 1645 Christchurch                Email : john.carter@tait.co.nz
New Zealand

Carter's Clarification of Murphy's Law.

"Things only ever go right so that they may go more spectacularly wrong
later."

From this principle, all of life and physics may be deduced.
98997c6ddfa98d33272d17a7de6e9749?d=identicon&s=25 Reto Schuettel (Guest)
on 2006-04-21 07:31
(Received via mailing list)
Hi John

On Fri, Apr 21, 2006 at 11:24:01AM +0900, John Carter wrote:
> functions on the STDIN/STDOUT fd's.
Or like ssh *gbrml*. ssh alway breaks out of my open3 and is able to
talk with the terminal directly. Is there no way to tell ssh to not use
the pty? With telnet it was fine...

> >Couldn't I use open3/open4 for the same purpose? I've
> >modified/extended the RExpect a little bit, so I'm alread used to the
> >internals, from my point of view I can't see any differences to the Open
> >libraries.
>
> I did make a (very small) start on a open3 interface to RExpect. If you
> feel like contributing your fixes back I would welcome them.

I'm currently hoping that nobu can fix the pty problem and I can switch
back to PTY.spawn(). I tried it with a modified version of open4 but it
caused more problem than it solved :/. I'm gonna diff original version
of Rexpec and mine version, and if there any any major 'enhancements'
I'm
happy to give them to you. E.g. I tried to get rid of the 'abort on
exception' thing because in my case Rexpect is used by a long-running
process. Errors should be packed into Exceptions and returned to the
program and all threads should be cleaned up.

> >I have to talk network devices (Cisco Router/Switches) over ssh/telnet
> >session (ssh prefered, of course ;)).
>
> I originally wrote rexpect to pretend to be lots and lots and lots of
> imaginary devices on the end of lots and lots of imaginary rs-232 lines.
>
> Currently my only use is to use 'ssh' to takeover my colleagues boxes
> and install, configure and run distcc on them.

I think one 'common' expect module would be very useful. At the moment
there are some projects like PTY.expect, Rexpect, yax (i think), but
none of these are really in a 'real' stable state. Perl has stable
Expect modules for years now... and they run on linux, solaris, whatever
without the need to touch the program.


Regards,
Reto
Schüttel
98997c6ddfa98d33272d17a7de6e9749?d=identicon&s=25 Reto Schuettel (Guest)
on 2006-04-21 14:41
(Received via mailing list)
Hi

Thanks for your answer!

On Fri, Apr 21, 2006 at 10:52:45AM +0900, nobu@ruby-lang.org wrote:
> Seems grantpt() on Solaris doesn't set errno perperly, or even
> the return value is not correct.
>
> Try this patch, but I don't know if it is in only particular
> version of Solaris, or more.

Okay! I've got now the problem... you're right, Solaris doesn't set the
errno (in this case), but it returns -1 if there was an error:

| Upon successful completion, grantpt() returns 0. Otherwise, it returns
| -1 and sets errno to indicate the error.
(Source: http://docs.sun.com/app/docs/doc/835-8004/6ruu29hdd?a=view)

I build a small grantpt example (using this manual) and then I was able
to reproduce this case where granpt returns -1 and doesn't set errno. I
did some more truss runs and then I found the soultion:

 | $ ls -al  /usr/lib/pt_chmod
 | ---x--x--x    1 root     bin          4488 Jul 27  2002
/usr/lib/pt_chmod

... pt_chmod isn't setuid root :/

Solaris Native System:
 | ---s--x--x   1 root     bin         4488 Apr 23  2002
/usr/lib/pt_chmod/pt_chmod

Setting the setuid bid solves the whole problem... DOH!

But, there's still another problem. The truss I sent in my last
email (when I was testing with root) showed the problem, it always just
returns 'EOFError' when I was reading from the filehandle.  But this
problem only occurs on some of our older systemms (old Solaris
patchlevel), so we're gonna updae these system and I hope that this
problem doesn't occur anymore.

Well.. this was never rubys fault :).. getpt() just fails in a very
unhelpy way (no errno).

Thanks for your help!
Reto
Schüttel
This topic is locked and can not be replied to.