Преглед изворни кода

* first (raw and ineffient) implementation

Michael Vogt пре 19 година
родитељ
комит
d8cb4aa445
3 измењених фајлова са 73 додато и 8 уклоњено
  1. 71 6
      apt-pkg/deb/dpkgpm.cc
  2. 1 1
      apt-pkg/makefile
  3. 1 1
      cmdline/makefile

+ 71 - 6
apt-pkg/deb/dpkgpm.cc

@@ -25,6 +25,11 @@
 #include <sstream>
 #include <map>
 
+#include <termios.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <pty.h>
+
 #include <config.h>
 #include <apti18n.h>
 									/*}}}*/
@@ -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)

+ 1 - 1
apt-pkg/makefile

@@ -15,7 +15,7 @@ LIBRARY=apt-pkg
 LIBEXT=$(GLIBC_VER)$(LIBSTDCPP_VER)
 MAJOR=4.4
 MINOR=0
-SLIBS=$(PTHREADLIB) $(INTLLIBS)
+SLIBS=$(PTHREADLIB) $(INTLLIBS) -lutil
 APT_DOMAIN:=libapt-pkg$(MAJOR)
 
 # Source code for the contributed non-core things

+ 1 - 1
cmdline/makefile

@@ -14,7 +14,7 @@ include $(PROGRAM_H)
 
 # The apt-get program
 PROGRAM=apt-get
-SLIBS = -lapt-pkg
+SLIBS = -lapt-pkg -lutil
 LIB_MAKES = apt-pkg/makefile
 SOURCE = apt-get.cc acqprogress.cc
 include $(PROGRAM_H)