#include <apt-pkg/depcache.h>
#include <apt-pkg/strutl.h>
#include <apti18n.h>
+#include <apt-pkg/fileutl.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <stdio.h>
+#include <string.h>
+#include <algorithm>
#include <sstream>
#include <map>
using namespace std;
-
+namespace
+{
+ // Maps the dpkg "processing" info to human readable names. Entry 0
+ // of each array is the key, entry 1 is the value.
+ const std::pair<const char *, const char *> PackageProcessingOps[] = {
+ std::make_pair("install", N_("Installing %s")),
+ std::make_pair("configure", N_("Configuring %s")),
+ std::make_pair("remove", N_("Removing %s")),
+ std::make_pair("trigproc", N_("Running post-installation trigger %s"))
+ };
+
+ const std::pair<const char *, const char *> * const PackageProcessingOpsBegin = PackageProcessingOps;
+ const std::pair<const char *, const char *> * const PackageProcessingOpsEnd = PackageProcessingOps + sizeof(PackageProcessingOps) / sizeof(PackageProcessingOps[0]);
+
+ // Predicate to test whether an entry in the PackageProcessingOps
+ // array matches a string.
+ class MatchProcessingOp
+ {
+ const char *target;
+
+ public:
+ MatchProcessingOp(const char *the_target)
+ : target(the_target)
+ {
+ }
+
+ bool operator()(const std::pair<const char *, const char *> &pair) const
+ {
+ return strcmp(pair.first, target) == 0;
+ }
+ };
+}
// DPkgPM::pkgDPkgPM - Constructor /*{{{*/
// ---------------------------------------------------------------------
return true;
}
/*}}}*/
-// DPkgPM::RunScripts - Run a set of scripts /*{{{*/
-// ---------------------------------------------------------------------
-/* This looks for a list of script sto run from the configuration file,
- each one is run with system from a forked child. */
-bool pkgDPkgPM::RunScripts(const char *Cnf)
-{
- Configuration::Item const *Opts = _config->Tree(Cnf);
- if (Opts == 0 || Opts->Child == 0)
- return true;
- Opts = Opts->Child;
-
- // Fork for running the system calls
- pid_t Child = ExecFork();
-
- // This is the child
- if (Child == 0)
- {
- if (chdir("/tmp/") != 0)
- _exit(100);
-
- unsigned int Count = 1;
- for (; Opts != 0; Opts = Opts->Next, Count++)
- {
- if (Opts->Value.empty() == true)
- continue;
-
- if (system(Opts->Value.c_str()) != 0)
- _exit(100+Count);
- }
- _exit(0);
- }
-
- // Wait for the child
- int Status = 0;
- while (waitpid(Child,&Status,0) != Child)
- {
- if (errno == EINTR)
- continue;
- return _error->Errno("waitpid","Couldn't wait for subprocess");
- }
-
- // Restore sig int/quit
- signal(SIGQUIT,SIG_DFL);
- signal(SIGINT,SIG_DFL);
-
- // Check for an error code.
- if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
- {
- unsigned int Count = WEXITSTATUS(Status);
- if (Count > 100)
- {
- Count -= 100;
- for (; Opts != 0 && Count != 1; Opts = Opts->Next, Count--);
- _error->Error("Problem executing scripts %s '%s'",Cnf,Opts->Value.c_str());
- }
-
- return _error->Error("Sub-process returned an error code");
- }
-
- return true;
-}
- /*}}}*/
// DPkgPM::SendV2Pkgs - Send version 2 package info /*{{{*/
// ---------------------------------------------------------------------
/* This is part of the helper script communication interface, it sends
*/
void pkgDPkgPM::DoStdin(int master)
{
- char input_buf[256] = {0,};
- int len = read(0, input_buf, sizeof(input_buf));
+ unsigned char input_buf[256] = {0,};
+ ssize_t len = read(0, input_buf, sizeof(input_buf));
if (len)
write(master, input_buf, len);
else
*/
void pkgDPkgPM::DoTerminalPty(int master)
{
- char term_buf[1024] = {0,};
+ unsigned char term_buf[1024] = {0,0, };
- int len=read(master, term_buf, sizeof(term_buf));
+ ssize_t len=read(master, term_buf, sizeof(term_buf));
if(len == -1 && errno == EIO)
{
// this happens when the child is about to exit, we
'status: /var/cache/apt/archives/krecipes_0.8.1-0ubuntu1_i386.deb : error : trying to overwrite `/usr/share/doc/kde/HTML/en/krecipes/krectip.png', which is also in package krecipes-data
and conffile-prompt like this
'status: conffile-prompt: conffile : 'current-conffile' 'new-conffile' useredited distedited
+
+ Newer versions of dpkg sent also:
+ 'processing: install: pkg'
+ 'processing: configure: pkg'
+ 'processing: remove: pkg'
+ 'processing: trigproc: trigger'
*/
char* list[5];
char *pkg = list[1];
char *action = _strstrip(list[2]);
+ // 'processing' from dpkg looks like
+ // 'processing: action: pkg'
+ if(strncmp(list[0], "processing", strlen("processing")) == 0)
+ {
+ char s[200];
+ char *pkg_or_trigger = _strstrip(list[2]);
+ action =_strstrip( list[1]);
+ const std::pair<const char *, const char *> * const iter =
+ std::find_if(PackageProcessingOpsBegin,
+ PackageProcessingOpsEnd,
+ MatchProcessingOp(action));
+ if(iter == PackageProcessingOpsEnd)
+ {
+ if (_config->FindB("Debug::pkgDPkgProgressReporting",false) == true)
+ std::clog << "ignoring unknwon action: " << action << std::endl;
+ return;
+ }
+ snprintf(s, sizeof(s), _(iter->second), pkg_or_trigger);
+
+ status << "pmstatus:" << pkg_or_trigger
+ << ":" << (PackagesDone/float(PackagesTotal)*100.0)
+ << ":" << s
+ << endl;
+ if(OutStatusFd > 0)
+ write(OutStatusFd, status.str().c_str(), status.str().size());
+ if (_config->FindB("Debug::pkgDPkgProgressReporting",false) == true)
+ std::clog << "send: '" << status.str() << "'" << endl;
+ return;
+ }
+
if(strncmp(action,"error",strlen("error")) == 0)
{
status << "pmerror:" << list[1]
struct tm *tmp = localtime(&t);
strftime(outstr, sizeof(outstr), "%F %T", tmp);
fprintf(term_out, "\nLog started: ");
- fprintf(term_out, outstr);
+ fprintf(term_out, "%s", outstr);
fprintf(term_out, "\n");
}
return true;
struct tm *tmp = localtime(&t);
strftime(outstr, sizeof(outstr), "%F %T", tmp);
fprintf(term_out, "Log ended: ");
- fprintf(term_out, outstr);
+ fprintf(term_out, "%s", outstr);
fprintf(term_out, "\n");
fclose(term_out);
}
*/
bool pkgDPkgPM::Go(int OutStatusFd)
{
+ fd_set rfds;
+ struct timespec tv;
+ sigset_t sigmask;
+ sigset_t original_sigmask;
+
unsigned int MaxArgs = _config->FindI("Dpkg::MaxArgs",8*1024);
unsigned int MaxArgBytes = _config->FindI("Dpkg::MaxArgBytes",32*1024);
+ bool NoTriggers = _config->FindB("DPkg::NoTriggers",false);
if (RunScripts("DPkg::Pre-Invoke") == false)
return false;
if (RunScriptsWithPkgs("DPkg::Pre-Install-Pkgs") == false)
return false;
-
+
// map the dpkg states to the operations that are performed
// (this is sorted in the same way as Item::Ops)
static const struct DpkgState DpkgStatesOpMap[][7] = {
case Item::Configure:
Args[n++] = "--configure";
+ if (NoTriggers)
+ Args[n++] = "--no-triggers";
Size += strlen(Args[n-1]);
break;
sighandler_t old_SIGINT = signal(SIGINT,SIG_IGN);
struct termios tt;
+ struct termios tt_out;
struct winsize win;
int master;
int slave;
// FIXME: setup sensible signal handling (*ick*)
tcgetattr(0, &tt);
+ tcgetattr(1, &tt_out);
ioctl(0, TIOCGWINSZ, (char *)&win);
- if (openpty(&master, &slave, NULL, &tt, &win) < 0)
+ if (openpty(&master, &slave, NULL, &tt_out, &win) < 0)
{
const char *s = _("Can not write log, openpty() "
"failed (/dev/pts not mounted?)\n");
rtt = tt;
cfmakeraw(&rtt);
rtt.c_lflag &= ~ECHO;
+ // 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);
}
// Fork dpkg
close(slave);
// setups fds
- fd_set rfds;
- struct timespec tv;
- sigset_t sigmask;
- sigset_t original_sigmask;
sigemptyset(&sigmask);
sigprocmask(SIG_BLOCK,&sigmask,&original_sigmask);
if (RunScripts("DPkg::Post-Invoke") == false)
return false;
+
+ Cache.writeStateFile(NULL);
return true;
}
/*}}}*/