Any and all opinions and advice on how this can be rewritten to
fix this problem (or work around it) are greatly appreciated.
Help me Obi-Wan Kenobi. You're my only hope.
Ron Stewart
Software Engineer
Lockheed Martin Mission Systems
The relevant code follows:
shell = getenv("SHELL");
if (shell == NULL)
shell = _PATH_BSHELL;
getmaster();
fixtty();
(void) signal(SIGCHLD, finish);
child = fork();
if (child < 0) {
perror("fork");
fail();
}
if (child == 0) {
subchild = child = fork();
if (child < 0) {
perror("fork");
fail();
}
if (child)
dooutput();
else
doshell();
} else
(void) signal(SIGWINCH, resize);
doinput();
----------------------------------------------------------------------------------
void
getmaster() {
char *pty, *bank, *cp;
struct stat stb;
pty = &line[strlen("/dev/ptyp")];
for (bank = "pqrs"; *bank; bank++) {
line[strlen("/dev/pty")] = *bank;
*pty = '0';
if (stat(line, &stb) < 0)
break;
for (cp = "0123456789abcdef"; *cp; cp++) {
*pty = *cp;
master = open(line, O_RDWR);
if (master >= 0) {
char *tp = &line[strlen("/dev/")];
int ok;
/* verify slave side is usable */
*tp = 't';
ok = access(line, R_OK|W_OK) == 0;
*tp = 'p';
if (ok) {
(void) tcgetattr(0, &tt);
(void) ioctl(0, TIOCGWINSZ,
(char *)&win);
return;
}
(void) close(master);
}
}
}
fprintf(stderr, _("Out of pty's\n"));
fail();
}
void
getslave() {
line[strlen("/dev/")] = 't';
slave = open(line, O_RDWR);
if (slave < 0) {
perror(line);
fail();
}
(void) tcsetattr(slave, TCSAFLUSH, &tt);
(void) ioctl(slave, TIOCSWINSZ, (char *)&win);
(void) setsid();
/* (void) ioctl(slave, TIOCSCTTY, 0); Here's where it sets
the
slave to be the
controlling term
*/
}
void
doinput() {
register int cc;
char ibuf[BUFSIZ];
while ((cc = read(0, ibuf, BUFSIZ)) > 0)
(void) write(master, ibuf, cc);
done();
}
void
dooutput() {
register int cc;
time_t tvec;
char obuf[BUFSIZ];
(void) close(0);
tvec = time((time_t *)NULL);
for (;;) {
cc = read(master, obuf, sizeof (obuf));
if (cc <= 0)
break;
(void) write(1, obuf, cc);
}
done();
}
void
doshell() {
getslave();
(void) close(master);
(void) dup2(slave, 0);
(void) dup2(slave, 1);
(void) dup2(slave, 2);
(void) close(slave);
execl(shell, "sh", "-i", 0);
perror(shell);
fail();
}
void
fixtty() {
struct termios rtt;
rtt = tt;
/* cfmakeraw(&rtt); */
/* This section added since Solaris does not support cfmakeraw
RES */
rtt.c_iflag &=
~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
rtt.c_oflag &= ~OPOST;
rtt.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN|FLUSHO);
rtt.c_cflag &= ~(CSIZE|PARENB);
rtt.c_cflag |= CS8;
rtt.c_lflag &= ~ECHO;
(void) tcsetattr(0, TCSAFLUSH, &rtt);
}
> The problem
> is that Solaris does not have a set controlling terminal option.
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.
If you'll be doing much UNIX programming, Stevens' _Advanced UNIX
Programming_ is a must-buy.
Richard Masoner