X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/b790b130ad0a43be5738c467c16bbc2dd657ca66..d8cb4aa44573aca621110fda47d72bd682c0e3f4:/apt-pkg/deb/dpkgpm.cc diff --git a/apt-pkg/deb/dpkgpm.cc b/apt-pkg/deb/dpkgpm.cc index 3204fc1bb..9ca519acd 100644 --- a/apt-pkg/deb/dpkgpm.cc +++ b/apt-pkg/deb/dpkgpm.cc @@ -8,9 +8,6 @@ ##################################################################### */ /*}}}*/ // Includes /*{{{*/ -#ifdef __GNUG__ -#pragma implementation "apt-pkg/dpkgpm.h" -#endif #include #include #include @@ -28,6 +25,11 @@ #include #include +#include +#include +#include +#include + #include #include /*}}}*/ @@ -474,6 +476,8 @@ bool pkgDPkgPM::Go(int OutStatusFd) case Item::Install: Args[n++] = "--unpack"; Size += strlen(Args[n-1]); + Args[n++] = "--auto-deconfigure"; + Size += strlen(Args[n-1]); break; } @@ -517,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]); @@ -526,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); @@ -546,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"); @@ -568,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 @@ -586,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) { @@ -703,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)