summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Vogt <mvo@debian.org>2013-10-31 21:03:33 +0100
committerMichael Vogt <mvo@debian.org>2013-10-31 21:03:33 +0100
commit177296dffd8bf7d9ce5870b135c412958aab3756 (patch)
treee44085cc6a25441d77f4cd5ac6aaee8ea804b32f
parentc5f0d8e6f8d338727b2b6bc4be0e482082398014 (diff)
parentc3045b79796b611858e9f8b44127a70d6043cea0 (diff)
move pty magic into its own functions
-rw-r--r--apt-pkg/deb/dpkgpm.cc183
-rw-r--r--apt-pkg/deb/dpkgpm.h2
2 files changed, 97 insertions, 88 deletions
diff --git a/apt-pkg/deb/dpkgpm.cc b/apt-pkg/deb/dpkgpm.cc
index b252c02eb..d1b11098c 100644
--- a/apt-pkg/deb/dpkgpm.cc
+++ b/apt-pkg/deb/dpkgpm.cc
@@ -55,7 +55,7 @@ class pkgDPkgPMPrivate
public:
pkgDPkgPMPrivate() : stdin_is_dev_null(false), dpkgbuf_pos(0),
term_out(NULL), history_out(NULL),
- progress(NULL)
+ progress(NULL), master(-1), slave(-1)
{
dpkgbuf[0] = '\0';
}
@@ -70,6 +70,16 @@ public:
FILE *history_out;
string dpkg_error;
APT::Progress::PackageManager *progress;
+
+ // pty stuff
+ struct termios tt;
+ int master;
+ int slave;
+
+ // signals
+ sigset_t sigmask;
+ sigset_t original_sigmask;
+
};
namespace
@@ -1013,6 +1023,58 @@ bool pkgDPkgPM::Go(int StatusFd)
}
#endif
+void pkgDPkgPM::StartPtyMagic()
+{
+ // setup the pty and stuff
+ struct winsize win;
+
+ // if tcgetattr does not return zero there was a error
+ // and we do not do any pty magic
+ _error->PushToStack();
+ if (tcgetattr(STDOUT_FILENO, &d->tt) == 0)
+ {
+ ioctl(1, TIOCGWINSZ, (char *)&win);
+ if (openpty(&d->master, &d->slave, NULL, &d->tt, &win) < 0)
+ {
+ _error->Errno("openpty", _("Can not write log (%s)"), _("Is /dev/pts mounted?"));
+ d->master = d->slave = -1;
+ } else {
+ struct termios rtt;
+ rtt = d->tt;
+ cfmakeraw(&rtt);
+ rtt.c_lflag &= ~ECHO;
+ rtt.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);
+ tcsetattr(0, TCSAFLUSH, &rtt);
+ sigprocmask(SIG_SETMASK, &d->original_sigmask, 0);
+ }
+ }
+ // 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.
+ else if (isatty(STDOUT_FILENO) == 1 || errno == EBADF)
+ _error->Errno("tcgetattr", _("Can not write log (%s)"), _("Is stdout a terminal?"));
+
+ if (_error->PendingError() == true)
+ _error->DumpErrors(std::cerr);
+ _error->RevertToStack();
+}
+
+void pkgDPkgPM::StopPtyMagic()
+{
+ if(d->slave > 0)
+ close(d->slave);
+ if(d->master >= 0)
+ {
+ tcsetattr(0, TCSAFLUSH, &d->tt);
+ close(d->master);
+ }
+}
+
// DPkgPM::Go - Run the sequence /*{{{*/
// ---------------------------------------------------------------------
/* This globs the operations and calls dpkg
@@ -1073,8 +1135,6 @@ bool pkgDPkgPM::GoNoABIBreak(APT::Progress::PackageManager *progress)
fd_set rfds;
struct timespec tv;
- sigset_t sigmask;
- sigset_t original_sigmask;
unsigned int const MaxArgs = _config->FindI("Dpkg::MaxArgs",8*1024);
unsigned int const MaxArgBytes = _config->FindI("Dpkg::MaxArgBytes",32*1024);
@@ -1116,7 +1176,13 @@ bool pkgDPkgPM::GoNoABIBreak(APT::Progress::PackageManager *progress)
dpkgMultiArch = true;
}
- // go over each item
+ // start pty magic before the loop
+ StartPtyMagic();
+
+ // Tell the progress that its starting and fork dpkg
+ d->progress->Start();
+
+ // this loop is runs once per dpkg operation
vector<Item>::const_iterator I = List.begin();
while (I != List.end())
{
@@ -1309,67 +1375,20 @@ bool pkgDPkgPM::GoNoABIBreak(APT::Progress::PackageManager *progress)
// ignore SIGHUP as well (debian #463030)
sighandler_t old_SIGHUP = signal(SIGHUP,SIG_IGN);
- struct termios tt;
- struct winsize win;
- int master = -1;
- int slave = -1;
-
- // if tcgetattr does not return zero there was a error
- // and we do not do any pty magic
- _error->PushToStack();
- if (tcgetattr(STDOUT_FILENO, &tt) == 0)
- {
- ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&win);
- if (openpty(&master, &slave, NULL, &tt, &win) < 0)
- {
- _error->Errno("openpty", _("Can not write log (%s)"), _("Is /dev/pts mounted?"));
- master = slave = -1;
- } else {
- struct termios rtt;
- rtt = tt;
- cfmakeraw(&rtt);
- rtt.c_lflag &= ~ECHO;
- rtt.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(&sigmask);
- sigaddset(&sigmask, SIGTTOU);
- sigprocmask(SIG_BLOCK,&sigmask, &original_sigmask);
- tcsetattr(0, TCSAFLUSH, &rtt);
- sigprocmask(SIG_SETMASK, &original_sigmask, 0);
- }
- }
- // 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.
- else if (isatty(STDOUT_FILENO) == 1 || errno == EBADF)
- _error->Errno("tcgetattr", _("Can not write log (%s)"), _("Is stdout a terminal?"));
-
- if (_error->PendingError() == true)
- _error->DumpErrors(std::cerr);
- _error->RevertToStack();
-
- // this is the dpkg status-fd, we need to keep it
- _config->Set("APT::Keep-Fds::",fd[1]);
-
- // Tell the progress that its starting and fork dpkg
- // FIXME: this is called once per dpkg run which is *too often*
- d->progress->Start();
-
pid_t Child = ExecFork();
// This is the child
if (Child == 0)
{
- if(slave >= 0 && master >= 0)
+ if(d->slave >= 0 && d->master >= 0)
{
setsid();
- ioctl(slave, TIOCSCTTY, 0);
- close(master);
- dup2(slave, 0);
- dup2(slave, 1);
- dup2(slave, 2);
- close(slave);
+ ioctl(d->slave, TIOCSCTTY, 0);
+ close(d->master);
+ dup2(d->slave, 0);
+ dup2(d->slave, 1);
+ dup2(d->slave, 2);
+ close(d->slave);
}
close(fd[0]); // close the read end of the pipe
@@ -1393,6 +1412,7 @@ bool pkgDPkgPM::GoNoABIBreak(APT::Progress::PackageManager *progress)
if (fcntl(STDIN_FILENO,F_SETFL,Flags & (~(long)O_NONBLOCK)) < 0)
_exit(100);
}
+
/* No Job Control Stop Env is a magic dpkg var that prevents it
from using sigstop */
putenv((char *)"DPKG_NO_TSTP=yes");
@@ -1415,12 +1435,9 @@ bool pkgDPkgPM::GoNoABIBreak(APT::Progress::PackageManager *progress)
int const _dpkgin = fd[0];
close(fd[1]); // close the write end of the pipe
- if(slave > 0)
- close(slave);
-
// setups fds
- sigemptyset(&sigmask);
- sigprocmask(SIG_BLOCK,&sigmask,&original_sigmask);
+ sigemptyset(&d->sigmask);
+ sigprocmask(SIG_BLOCK,&d->sigmask,&d->original_sigmask);
/* free vectors (and therefore memory) as we don't need the included data anymore */
for (std::vector<char *>::const_iterator p = Packages.begin();
@@ -1449,21 +1466,18 @@ bool pkgDPkgPM::GoNoABIBreak(APT::Progress::PackageManager *progress)
// wait for input or output here
FD_ZERO(&rfds);
- if (master >= 0 && !d->stdin_is_dev_null)
+ if (d->master >= 0 && !d->stdin_is_dev_null)
FD_SET(0, &rfds);
FD_SET(_dpkgin, &rfds);
- if(master >= 0)
- FD_SET(master, &rfds);
- tv.tv_sec = 0;
- tv.tv_nsec = d->progress->GetPulseInterval();
- select_ret = pselect(max(master, _dpkgin)+1, &rfds, NULL, NULL,
- &tv, &original_sigmask);
+ if(d->master >= 0)
+ FD_SET(d->master, &rfds);
+ tv.tv_sec = 1;
+ tv.tv_nsec = 0;
+ select_ret = pselect(max(d->master, _dpkgin)+1, &rfds, NULL, NULL,
+ &tv, &d->original_sigmask);
if (select_ret < 0 && (errno == EINVAL || errno == ENOSYS))
- select_ret = racy_pselect(max(master, _dpkgin)+1, &rfds, NULL,
- NULL, &tv, &original_sigmask);
-
- d->progress->Pulse();
-
+ select_ret = racy_pselect(max(d->master, _dpkgin)+1, &rfds, NULL,
+ NULL, &tv, &d->original_sigmask);
if (select_ret == 0)
continue;
else if (select_ret < 0 && errno == EINTR)
@@ -1474,10 +1488,10 @@ bool pkgDPkgPM::GoNoABIBreak(APT::Progress::PackageManager *progress)
continue;
}
- if(master >= 0 && FD_ISSET(master, &rfds))
- DoTerminalPty(master);
- if(master >= 0 && FD_ISSET(0, &rfds))
- DoStdin(master);
+ if(d->master >= 0 && FD_ISSET(d->master, &rfds))
+ DoTerminalPty(d->master);
+ if(d->master >= 0 && FD_ISSET(0, &rfds))
+ DoStdin(d->master);
if(FD_ISSET(_dpkgin, &rfds))
DoDpkgStatusFd(_dpkgin);
}
@@ -1488,13 +1502,6 @@ bool pkgDPkgPM::GoNoABIBreak(APT::Progress::PackageManager *progress)
signal(SIGINT,old_SIGINT);
signal(SIGHUP,old_SIGHUP);
-
- if(master >= 0)
- {
- tcsetattr(0, TCSAFLUSH, &tt);
- close(master);
- }
-
// Check for an error code.
if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
{
@@ -1524,10 +1531,10 @@ bool pkgDPkgPM::GoNoABIBreak(APT::Progress::PackageManager *progress)
}
}
}
- CloseLog();
-
// dpkg is done at this point
d->progress->Stop();
+ StopPtyMagic();
+ CloseLog();
if (pkgPackageManager::SigINTStop)
_error->Warning(_("Operation was interrupted before it could finish"));
diff --git a/apt-pkg/deb/dpkgpm.h b/apt-pkg/deb/dpkgpm.h
index 50b5d609b..06318d94f 100644
--- a/apt-pkg/deb/dpkgpm.h
+++ b/apt-pkg/deb/dpkgpm.h
@@ -101,6 +101,8 @@ class pkgDPkgPM : public pkgPackageManager
// helper
void BuildPackagesProgressMap();
+ void StartPtyMagic();
+ void StopPtyMagic();
// input processing
void DoStdin(int master);