From d8cb4aa44573aca621110fda47d72bd682c0e3f4 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Tue, 3 Jul 2007 21:38:32 +0200 Subject: * first (raw and ineffient) implementation --- apt-pkg/deb/dpkgpm.cc | 77 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 71 insertions(+), 6 deletions(-) (limited to 'apt-pkg/deb/dpkgpm.cc') diff --git a/apt-pkg/deb/dpkgpm.cc b/apt-pkg/deb/dpkgpm.cc index e5506d3bf..9ca519acd 100644 --- a/apt-pkg/deb/dpkgpm.cc +++ b/apt-pkg/deb/dpkgpm.cc @@ -25,6 +25,11 @@ #include #include +#include +#include +#include +#include + #include #include /*}}}*/ @@ -516,7 +521,24 @@ bool pkgDPkgPM::Go(int OutStatusFd) it doesn't die but we do! So we must also ignore it */ sighandler_t old_SIGQUIT = signal(SIGQUIT,SIG_IGN); sighandler_t old_SIGINT = signal(SIGINT,SIG_IGN); - + + struct termios tt; + struct winsize win; + int master; + int slave; + + tcgetattr(0, &tt); + ioctl(0, TIOCGWINSZ, (char *)&win); + if (openpty(&master, &slave, NULL, &tt, &win) < 0) { + fprintf(stderr, _("openpty failed\n")); + } + + struct termios rtt; + rtt = tt; + cfmakeraw(&rtt); + rtt.c_lflag &= ~ECHO; + tcsetattr(0, TCSAFLUSH, &rtt); + // Fork dpkg pid_t Child; _config->Set("APT::Keep-Fds::",fd[1]); @@ -525,8 +547,16 @@ bool pkgDPkgPM::Go(int OutStatusFd) // This is the child if (Child == 0) { + setsid(); + ioctl(slave, TIOCSCTTY, 0); + close(master); + dup2(slave, 0); + dup2(slave, 1); + dup2(slave, 2); + close(slave); + close(fd[0]); // close the read end of the pipe - + if (chdir(_config->FindDir("DPkg::Run-Directory","/").c_str()) != 0) _exit(100); @@ -545,7 +575,8 @@ bool pkgDPkgPM::Go(int OutStatusFd) 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("DPKG_NO_TSTP=yes"); @@ -567,11 +598,19 @@ bool pkgDPkgPM::Go(int OutStatusFd) // the read buffers for the communication with dpkg char line[1024] = {0,}; + char buf[2] = {0,0}; + char term_buf[2] = {0,0}; + char input_buf[2] = {0,0}; // the result of the waitpid call int res; - + close(slave); + fcntl(0, F_SETFL, O_NONBLOCK); + fcntl(master, F_SETFL, O_NONBLOCK); + FILE *term_out = fopen("/var/log/dpkg-out.log","a"); + chmod("/var/log/dpkg-out.log", 0600); + while ((res=waitpid(Child,&Status, WNOHANG)) != Child) { if(res < 0) { // FIXME: move this to a function or something, looks ugly here @@ -585,18 +624,41 @@ bool pkgDPkgPM::Go(int OutStatusFd) signal(SIGINT,old_SIGINT); return _error->Errno("waitpid","Couldn't wait for subprocess"); } + + // wait for input or output here + + // FIXME: use select() instead of the rubish below // read a single char, make sure that the read can't block // (otherwise we may leave zombies) + int term_len = read(master, term_buf, 1); + int input_len = read(0, input_buf, 1); int len = read(_dpkgin, buf, 1); - // nothing to read, wait a bit for more + // see if we have any input that needs to go to the + // master pty + if(input_len > 0) + write(master, input_buf, 1); + + // see if we have any output that needs to be echoed + // and written to the log + if(term_len > 0) + { + do + { + fwrite(term_buf, 1, 1, term_out); + write(1, term_buf, 1); + } while(read(master, term_buf, 1) > 0); + term_buf[0] = 0; + } + + // nothing to read from dpkg , wait a bit for more if(len <= 0) { usleep(1000); continue; } - + // sanity check (should never happen) if(strlen(line) >= sizeof(line)-10) { @@ -702,10 +764,13 @@ bool pkgDPkgPM::Go(int OutStatusFd) line[0]=0; } close(_dpkgin); + fclose(term_out); // Restore sig int/quit signal(SIGQUIT,old_SIGQUIT); signal(SIGINT,old_SIGINT); + + tcsetattr(0, TCSAFLUSH, &tt); // Check for an error code. if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0) -- cgit v1.2.3