+
+ _error->PushToStack();
+ // if tcgetattr for both stdin/stdout returns 0 (no error)
+ // we do the pty magic
+ if (tcgetattr(STDOUT_FILENO, &d->tt) == 0 &&
+ tcgetattr(STDIN_FILENO, &d->tt) == 0)
+ {
+ d->master = posix_openpt(O_RDWR | O_NOCTTY);
+ if (d->master == -1)
+ _error->Errno("posix_openpt", _("Can not write log (%s)"), _("Is /dev/pts mounted?"));
+ else if (unlockpt(d->master) == -1)
+ {
+ _error->Errno("unlockpt", "Unlocking the slave of master fd %d failed!", d->master);
+ close(d->master);
+ d->master = -1;
+ }
+ else
+ {
+ char const * const slave_name = ptsname(d->master);
+ if (slave_name == NULL)
+ {
+ _error->Errno("unlockpt", "Getting name for slave of master fd %d failed!", d->master);
+ close(d->master);
+ d->master = -1;
+ }
+ else
+ {
+ d->slave = strdup(slave_name);
+ if (d->slave == NULL)
+ {
+ _error->Errno("strdup", "Copying name %s for slave of master fd %d failed!", slave_name, d->master);
+ close(d->master);
+ d->master = -1;
+ }
+ struct winsize win;
+ if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) < 0)
+ _error->Errno("ioctl", "Getting TIOCGWINSZ from stdout failed!");
+ if (ioctl(d->master, TIOCSWINSZ, &win) < 0)
+ _error->Errno("ioctl", "Setting TIOCSWINSZ for master fd %d failed!", d->master);
+ if (tcsetattr(d->master, TCSANOW, &d->tt) == -1)
+ _error->Errno("tcsetattr", "Setting in Start via TCSANOW for master fd %d failed!", d->master);
+
+ struct termios raw_tt;
+ raw_tt = d->tt;
+ cfmakeraw(&raw_tt);
+ raw_tt.c_lflag &= ~ECHO;
+ raw_tt.c_lflag |= ISIG;
+ // block SIGTTOU during tcsetattr to prevent a hang if
+ // the process is a member of the background process group
+ // http://www.opengroup.org/onlinepubs/000095399/functions/tcsetattr.html
+ sigemptyset(&d->sigmask);
+ sigaddset(&d->sigmask, SIGTTOU);
+ sigprocmask(SIG_BLOCK,&d->sigmask, &d->original_sigmask);
+ if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw_tt) == -1)
+ _error->Errno("tcsetattr", "Setting in Start via TCSAFLUSH for stdout failed!");
+ sigprocmask(SIG_SETMASK, &d->original_sigmask, NULL);
+ }
+ }
+ }
+ else
+ {
+ // complain only if stdout is either a terminal (but still failed) or is an invalid
+ // descriptor otherwise we would complain about redirection to e.g. /dev/null as well.
+ if (isatty(STDOUT_FILENO) == 1 || errno == EBADF)
+ _error->Errno("tcgetattr", _("Can not write log (%s)"), _("Is stdout a terminal?"));
+ }
+
+ if (_error->PendingError() == true)
+ {
+ if (d->master != -1)
+ {
+ close(d->master);
+ d->master = -1;
+ }
+ _error->DumpErrors(std::cerr);
+ }
+ _error->RevertToStack();