|
@@ -25,6 +25,11 @@
|
|
|
#include <sstream>
|
|
#include <sstream>
|
|
|
#include <map>
|
|
#include <map>
|
|
|
|
|
|
|
|
|
|
+#include <termios.h>
|
|
|
|
|
+#include <unistd.h>
|
|
|
|
|
+#include <sys/ioctl.h>
|
|
|
|
|
+#include <pty.h>
|
|
|
|
|
+
|
|
|
#include <config.h>
|
|
#include <config.h>
|
|
|
#include <apti18n.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 */
|
|
it doesn't die but we do! So we must also ignore it */
|
|
|
sighandler_t old_SIGQUIT = signal(SIGQUIT,SIG_IGN);
|
|
sighandler_t old_SIGQUIT = signal(SIGQUIT,SIG_IGN);
|
|
|
sighandler_t old_SIGINT = signal(SIGINT,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
|
|
// Fork dpkg
|
|
|
pid_t Child;
|
|
pid_t Child;
|
|
|
_config->Set("APT::Keep-Fds::",fd[1]);
|
|
_config->Set("APT::Keep-Fds::",fd[1]);
|
|
@@ -525,8 +547,16 @@ bool pkgDPkgPM::Go(int OutStatusFd)
|
|
|
// This is the child
|
|
// This is the child
|
|
|
if (Child == 0)
|
|
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
|
|
close(fd[0]); // close the read end of the pipe
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (chdir(_config->FindDir("DPkg::Run-Directory","/").c_str()) != 0)
|
|
if (chdir(_config->FindDir("DPkg::Run-Directory","/").c_str()) != 0)
|
|
|
_exit(100);
|
|
_exit(100);
|
|
|
|
|
|
|
@@ -545,7 +575,8 @@ bool pkgDPkgPM::Go(int OutStatusFd)
|
|
|
if (fcntl(STDIN_FILENO,F_SETFL,Flags & (~(long)O_NONBLOCK)) < 0)
|
|
if (fcntl(STDIN_FILENO,F_SETFL,Flags & (~(long)O_NONBLOCK)) < 0)
|
|
|
_exit(100);
|
|
_exit(100);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
/* No Job Control Stop Env is a magic dpkg var that prevents it
|
|
/* No Job Control Stop Env is a magic dpkg var that prevents it
|
|
|
from using sigstop */
|
|
from using sigstop */
|
|
|
putenv("DPKG_NO_TSTP=yes");
|
|
putenv("DPKG_NO_TSTP=yes");
|
|
@@ -567,11 +598,19 @@ bool pkgDPkgPM::Go(int OutStatusFd)
|
|
|
|
|
|
|
|
// the read buffers for the communication with dpkg
|
|
// the read buffers for the communication with dpkg
|
|
|
char line[1024] = {0,};
|
|
char line[1024] = {0,};
|
|
|
|
|
+
|
|
|
char buf[2] = {0,0};
|
|
char buf[2] = {0,0};
|
|
|
|
|
+ char term_buf[2] = {0,0};
|
|
|
|
|
+ char input_buf[2] = {0,0};
|
|
|
|
|
|
|
|
// the result of the waitpid call
|
|
// the result of the waitpid call
|
|
|
int res;
|
|
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) {
|
|
while ((res=waitpid(Child,&Status, WNOHANG)) != Child) {
|
|
|
if(res < 0) {
|
|
if(res < 0) {
|
|
|
// FIXME: move this to a function or something, looks ugly here
|
|
// FIXME: move this to a function or something, looks ugly here
|
|
@@ -585,18 +624,41 @@ bool pkgDPkgPM::Go(int OutStatusFd)
|
|
|
signal(SIGINT,old_SIGINT);
|
|
signal(SIGINT,old_SIGINT);
|
|
|
return _error->Errno("waitpid","Couldn't wait for subprocess");
|
|
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
|
|
// read a single char, make sure that the read can't block
|
|
|
// (otherwise we may leave zombies)
|
|
// (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);
|
|
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)
|
|
if(len <= 0)
|
|
|
{
|
|
{
|
|
|
usleep(1000);
|
|
usleep(1000);
|
|
|
continue;
|
|
continue;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// sanity check (should never happen)
|
|
// sanity check (should never happen)
|
|
|
if(strlen(line) >= sizeof(line)-10)
|
|
if(strlen(line) >= sizeof(line)-10)
|
|
|
{
|
|
{
|
|
@@ -702,10 +764,13 @@ bool pkgDPkgPM::Go(int OutStatusFd)
|
|
|
line[0]=0;
|
|
line[0]=0;
|
|
|
}
|
|
}
|
|
|
close(_dpkgin);
|
|
close(_dpkgin);
|
|
|
|
|
+ fclose(term_out);
|
|
|
|
|
|
|
|
// Restore sig int/quit
|
|
// Restore sig int/quit
|
|
|
signal(SIGQUIT,old_SIGQUIT);
|
|
signal(SIGQUIT,old_SIGQUIT);
|
|
|
signal(SIGINT,old_SIGINT);
|
|
signal(SIGINT,old_SIGINT);
|
|
|
|
|
+
|
|
|
|
|
+ tcsetattr(0, TCSAFLUSH, &tt);
|
|
|
|
|
|
|
|
// Check for an error code.
|
|
// Check for an error code.
|
|
|
if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
|
|
if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
|