Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

exp_spawnv() never closes master pty if child fails to execute

21 views
Skip to first unread message

ko1...@verizon.net

unread,
Apr 19, 2007, 11:29:24 AM4/19/07
to don....@nist.gov
I am running lib_expect with C, and I have compared the results that I
am getting with the exp_clib.c source code and seem to have found an
issue, but if this is a known issue, please let me know. I've
searched but with no real substantial hits on this particular issue.

I have a long running Unix (AIX) process that is using exp_spawnl()
with an invalid filename. In doing this, I found that the master
PTY's were never getting freed/closed. With a valid file name, it
does get freed as the lib sets the master pty to close on exec.
However, with the invalid filename, when the exec fails, exp_pty[0]
(master) gets set to -1 and it returns -1, however, it never closes
exp_pty[0] first. I am unable to close it later (without ending the
process) since I don't have the file descriptor (it is now -1).

Since this is a long running unix process, eventually, all of the
master PTY's get used since it has a fixed amount.

By the way, I am obviously not intending to have the expect use a bad
filename. I created the code, but then installed it on a system that
did not yet have the other half (the file used in exp_spawnl())
installed yet. I thought that it could run like that for a while and
just printed the -1 result from exp_spawnl() in my logs. As a work-
around, I will add code to see if the filename exists first, and if
not, I will not call the exp_spawnl() code. However, if anyone can
provide input, that is welcome.

In exp_clib.c, I saw the following:

First, exp_spawnl() reall calls exp_spawnv(). At then end of the
exp_spawnv() process, I saw the following. Notice the code in the
default section never does a close on pty[0], so the master is never
freed. However, it resets the value to -1 so I cannot reference what
it was.

exp_spawnv() {......
retry:
switch (read(status_pipe[0],&child_errno,sizeof child_errno)) {
case -1:
if (errno == EINTR) goto retry;
/* well it's not really the child's errno */
/* but it can be treated that way */
child_errno = errno;
break;
case 0:
/* child's exec succeeded */
child_errno = 0;
break;
default:
/* child's exec failed; err contains exec's errno */
waitpid(exp_pid, NULL, 0);
errno = child_errno;
exp_pty[0] = -1;
}
close(status_pipe[0]);
return(exp_pty[0]);
}

0 new messages