+bool pkgDPkgPM::Go(int StatusFd) /*{{{*/
+{
+ APT::Progress::PackageManager *progress = NULL;
+ if (StatusFd == -1)
+ progress = APT::Progress::PackageManagerProgressFactory();
+ else
+ progress = new APT::Progress::PackageManagerProgressFd(StatusFd);
+
+ return Go(progress);
+}
+ /*}}}*/
+void pkgDPkgPM::StartPtyMagic() /*{{{*/
+{
+ if (_config->FindB("Dpkg::Use-Pty", true) == false)
+ {
+ d->master = -1;
+ if (d->slave != NULL)
+ free(d->slave);
+ d->slave = NULL;
+ return;
+ }
+
+ if (isatty(STDIN_FILENO) == 0)
+ d->direct_stdin = true;
+
+ _error->PushToStack();
+
+ 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);
+ else
+ {
+#ifdef HAVE_PTS_NAME_R
+ char slave_name[64]; // 64 is used by bionic
+ if (ptsname_r(d->master, slave_name, sizeof(slave_name)) != 0)
+#else
+ char const * const slave_name = ptsname(d->master);
+ if (slave_name == NULL)
+#endif
+ _error->Errno("ptsname", "Getting name for slave of master fd %d failed!", d->master);
+ 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);
+ else if (grantpt(d->master) == -1)
+ _error->Errno("grantpt", "Granting access to slave %s based on master fd %d failed!", slave_name, d->master);
+ else if (tcgetattr(STDIN_FILENO, &d->tt) == 0)
+ {
+ d->tt_is_valid = true;
+ struct termios raw_tt;
+ // copy window size of stdout if its a 'good' terminal
+ if (tcgetattr(STDOUT_FILENO, &raw_tt) == 0)
+ {
+ 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);
+
+ 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 stdin failed!");
+ sigprocmask(SIG_SETMASK, &d->original_sigmask, NULL);
+
+ }
+ if (d->slave != NULL)
+ {
+ /* on linux, closing (and later reopening) all references to the slave
+ makes the slave a death end, so we open it here to have one open all
+ the time. We could use this fd in SetupSlavePtyMagic() for linux, but
+ on kfreebsd we get an incorrect ("step like") output then while it has
+ no problem with closing all references… so to avoid platform specific
+ code here we combine both and be happy once more */
+ d->protect_slave_from_dying = open(d->slave, O_RDWR | O_CLOEXEC | O_NOCTTY);
+ }
+ }
+ }
+
+ if (_error->PendingError() == true)
+ {
+ if (d->master != -1)
+ {
+ close(d->master);
+ d->master = -1;
+ }
+ if (d->slave != NULL)
+ {
+ free(d->slave);
+ d->slave = NULL;
+ }
+ _error->DumpErrors(std::cerr, GlobalError::DEBUG, false);
+ }
+ _error->RevertToStack();
+}
+ /*}}}*/
+void pkgDPkgPM::SetupSlavePtyMagic() /*{{{*/
+{
+ if(d->master == -1 || d->slave == NULL)
+ return;
+
+ if (close(d->master) == -1)
+ _error->FatalE("close", "Closing master %d in child failed!", d->master);
+ d->master = -1;
+ if (setsid() == -1)
+ _error->FatalE("setsid", "Starting a new session for child failed!");
+
+ int const slaveFd = open(d->slave, O_RDWR | O_NOCTTY);
+ if (slaveFd == -1)
+ _error->FatalE("open", _("Can not write log (%s)"), _("Is /dev/pts mounted?"));
+ else if (ioctl(slaveFd, TIOCSCTTY, 0) < 0)
+ _error->FatalE("ioctl", "Setting TIOCSCTTY for slave fd %d failed!", slaveFd);
+ else
+ {
+ unsigned short i = 0;
+ if (d->direct_stdin == true)
+ ++i;
+ for (; i < 3; ++i)
+ if (dup2(slaveFd, i) == -1)
+ _error->FatalE("dup2", "Dupping %d to %d in child failed!", slaveFd, i);
+
+ if (d->tt_is_valid == true && tcsetattr(STDIN_FILENO, TCSANOW, &d->tt) < 0)
+ _error->FatalE("tcsetattr", "Setting in Setup via TCSANOW for slave fd %d failed!", slaveFd);
+ }
+
+ if (slaveFd != -1)
+ close(slaveFd);
+}
+ /*}}}*/
+void pkgDPkgPM::StopPtyMagic() /*{{{*/
+{
+ if (d->slave != NULL)
+ free(d->slave);
+ d->slave = NULL;
+ if (d->protect_slave_from_dying != -1)
+ {
+ close(d->protect_slave_from_dying);
+ d->protect_slave_from_dying = -1;
+ }
+ if(d->master >= 0)
+ {
+ if (d->tt_is_valid == true && tcsetattr(STDIN_FILENO, TCSAFLUSH, &d->tt) == -1)
+ _error->FatalE("tcsetattr", "Setting in Stop via TCSAFLUSH for stdin failed!");
+ close(d->master);
+ d->master = -1;
+ }
+}
+