Strange problem with PTY.spawn()

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 S.

On Tue, Apr 11, 2006 at 12:06:56AM +0900, Reto S. wrote:

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

grmbl and here it is … :confused: (I hope the ML doesn’t reject mails with
attachements).

Hi,

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

On Tue, Apr 11, 2006 at 12:06:56AM +0900, Reto S. 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 S.

[1] Spam Spam Spam Spam Spammity spam - YouTube

On Tue, 11 Apr 2006, Reto S. 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 S.

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

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.

Hi,

At Tue, 11 Apr 2006 00:22:42 +0900,
Reto S. 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 … :confused: (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;

Hi Bruce

On Tue, Apr 11, 2006 at 07:12:54AM +0900, Bruce W. 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 :slight_smile: … but thanks
anyway.

Cheers,
Reto
Schüttel

Hi Nobu

Sorry for the long delay!

On Tue, Apr 11, 2006 at 10:52:03PM +0900, [email protected] 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

Hi

On Tue, Apr 18, 2006 at 06:15:14PM +0900, Reto S. 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… :confused:

I really don’t get it… im completly out of ideas…

Please tell me if you need anything else.

Regards,
Reto Schüttel

Hi,

At Thu, 20 Apr 2006 23:42:03 +0900,
Reto S. 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) {

On Tue, 11 Apr 2006, Reto S. 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 C. Phone : (64)(3) 358 6639
Tait Electronics Fax : (64)(3) 359 4632
PO Box 1645 Christchurch Email : [email protected]
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.

Hi

Thanks for your answer!

On Fri, Apr 21, 2006 at 10:52:45AM +0900, [email protected] 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 :confused:

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

Hi John

On Fri, Apr 21, 2006 at 11:24:01AM +0900, John C. 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