X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/ddc1d8d08eaff6c71c6062654ddd9d8981799ae9..e9b0cab795afa27f50ee30708e090962a806c6fa:/apt-pkg/deb/dpkgpm.cc diff --git a/apt-pkg/deb/dpkgpm.cc b/apt-pkg/deb/dpkgpm.cc index 7645929db..70c78fbb7 100644 --- a/apt-pkg/deb/dpkgpm.cc +++ b/apt-pkg/deb/dpkgpm.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: dpkgpm.cc,v 1.12 1999/07/26 17:46:08 jgg Exp $ +// $Id: dpkgpm.cc,v 1.25 2002/04/24 05:40:47 jgg Exp $ /* ###################################################################### DPKG Package Manager - Provide an interface to dpkg @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include @@ -22,12 +24,16 @@ #include #include #include +#include +#include /*}}}*/ +using namespace std; + // DPkgPM::pkgDPkgPM - Constructor /*{{{*/ // --------------------------------------------------------------------- /* */ -pkgDPkgPM::pkgDPkgPM(pkgDepCache &Cache) : pkgPackageManager(Cache) +pkgDPkgPM::pkgDPkgPM(pkgDepCache *Cache) : pkgPackageManager(Cache) { } /*}}}*/ @@ -136,6 +142,184 @@ bool pkgDPkgPM::RunScripts(const char *Cnf) 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 + very complete information down to the other end of the pipe.*/ +bool pkgDPkgPM::SendV2Pkgs(FILE *F) +{ + fprintf(F,"VERSION 2\n"); + + /* Write out all of the configuration directives by walking the + configuration tree */ + const Configuration::Item *Top = _config->Tree(0); + for (; Top != 0;) + { + if (Top->Value.empty() == false) + { + fprintf(F,"%s=%s\n", + QuoteString(Top->FullTag(),"=\"\n").c_str(), + QuoteString(Top->Value,"\n").c_str()); + } + + if (Top->Child != 0) + { + Top = Top->Child; + continue; + } + + while (Top != 0 && Top->Next == 0) + Top = Top->Parent; + if (Top != 0) + Top = Top->Next; + } + fprintf(F,"\n"); + + // Write out the package actions in order. + for (vector::iterator I = List.begin(); I != List.end(); I++) + { + pkgDepCache::StateCache &S = Cache[I->Pkg]; + + fprintf(F,"%s ",I->Pkg.Name()); + // Current version + if (I->Pkg->CurrentVer == 0) + fprintf(F,"- "); + else + fprintf(F,"%s ",I->Pkg.CurrentVer().VerStr()); + + // Show the compare operator + // Target version + if (S.InstallVer != 0) + { + int Comp = 2; + if (I->Pkg->CurrentVer != 0) + Comp = S.InstVerIter(Cache).CompareVer(I->Pkg.CurrentVer()); + if (Comp < 0) + fprintf(F,"> "); + if (Comp == 0) + fprintf(F,"= "); + if (Comp > 0) + fprintf(F,"< "); + fprintf(F,"%s ",S.InstVerIter(Cache).VerStr()); + } + else + fprintf(F,"> - "); + + // Show the filename/operation + if (I->Op == Item::Install) + { + // No errors here.. + if (I->File[0] != '/') + fprintf(F,"**ERROR**\n"); + else + fprintf(F,"%s\n",I->File.c_str()); + } + if (I->Op == Item::Configure) + fprintf(F,"**CONFIGURE**\n"); + if (I->Op == Item::Remove || + I->Op == Item::Purge) + fprintf(F,"**REMOVE**\n"); + + if (ferror(F) != 0) + return false; + } + return true; +} + /*}}}*/ +// DPkgPM::RunScriptsWithPkgs - Run scripts with package names on stdin /*{{{*/ +// --------------------------------------------------------------------- +/* This looks for a list of scripts to run from the configuration file + each one is run and is fed on standard input a list of all .deb files + that are due to be installed. */ +bool pkgDPkgPM::RunScriptsWithPkgs(const char *Cnf) +{ + Configuration::Item const *Opts = _config->Tree(Cnf); + if (Opts == 0 || Opts->Child == 0) + return true; + Opts = Opts->Child; + + unsigned int Count = 1; + for (; Opts != 0; Opts = Opts->Next, Count++) + { + if (Opts->Value.empty() == true) + continue; + + // Determine the protocol version + string OptSec = Opts->Value; + string::size_type Pos; + if ((Pos = OptSec.find(' ')) == string::npos || Pos == 0) + Pos = OptSec.length(); + OptSec = "DPkg::Tools::Options::" + string(Opts->Value.c_str(),Pos); + + unsigned int Version = _config->FindI(OptSec+"::Version",1); + + // Create the pipes + int Pipes[2]; + if (pipe(Pipes) != 0) + return _error->Errno("pipe","Failed to create IPC pipe to subprocess"); + SetCloseExec(Pipes[0],true); + SetCloseExec(Pipes[1],true); + + // Purified Fork for running the script + pid_t Process = ExecFork(); + if (Process == 0) + { + // Setup the FDs + dup2(Pipes[0],STDIN_FILENO); + SetCloseExec(STDOUT_FILENO,false); + SetCloseExec(STDIN_FILENO,false); + SetCloseExec(STDERR_FILENO,false); + + const char *Args[4]; + Args[0] = "/bin/sh"; + Args[1] = "-c"; + Args[2] = Opts->Value.c_str(); + Args[3] = 0; + execv(Args[0],(char **)Args); + _exit(100); + } + close(Pipes[0]); + FILE *F = fdopen(Pipes[1],"w"); + if (F == 0) + return _error->Errno("fdopen","Faild to open new FD"); + + // Feed it the filenames. + bool Die = false; + if (Version <= 1) + { + for (vector::iterator I = List.begin(); I != List.end(); I++) + { + // Only deal with packages to be installed from .deb + if (I->Op != Item::Install) + continue; + + // No errors here.. + if (I->File[0] != '/') + continue; + + /* Feed the filename of each package that is pending install + into the pipe. */ + fprintf(F,"%s\n",I->File.c_str()); + if (ferror(F) != 0) + { + Die = true; + break; + } + } + } + else + Die = !SendV2Pkgs(F); + + fclose(F); + + // Clean up the sub process + if (ExecWait(Process,Opts->Value.c_str()) == false) + return _error->Error("Failure running script %s",Opts->Value.c_str()); + } + return true; } /*}}}*/ @@ -144,22 +328,29 @@ bool pkgDPkgPM::RunScripts(const char *Cnf) /* This globs the operations and calls dpkg */ bool pkgDPkgPM::Go() { + unsigned int MaxArgs = _config->FindI("Dpkg::MaxArgs",350); + unsigned int MaxArgBytes = _config->FindI("Dpkg::MaxArgBytes",1024); + if (RunScripts("DPkg::Pre-Invoke") == false) return false; - + + if (RunScriptsWithPkgs("DPkg::Pre-Install-Pkgs") == false) + return false; + for (vector::iterator I = List.begin(); I != List.end();) { vector::iterator J = I; for (; J != List.end() && J->Op == I->Op; J++); // Generate the argument list - const char *Args[400]; - if (J - I > 350) - J = I + 350; + const char *Args[MaxArgs + 50]; + if (J - I > (signed)MaxArgs) + J = I + MaxArgs; unsigned int n = 0; unsigned long Size = 0; - Args[n++] = _config->Find("Dir::Bin::dpkg","dpkg").c_str(); + string Tmp = _config->Find("Dir::Bin::dpkg","dpkg"); + Args[n++] = Tmp.c_str(); Size += strlen(Args[n-1]); // Stick in any custom dpkg options @@ -210,7 +401,7 @@ bool pkgDPkgPM::Go() // Write in the file or package names if (I->Op == Item::Install) { - for (;I != J && Size < 1024; I++) + for (;I != J && Size < MaxArgBytes; I++) { if (I->File[0] != '/') return _error->Error("Internal Error, Pathname to install is not absolute '%s'",I->File.c_str()); @@ -220,7 +411,7 @@ bool pkgDPkgPM::Go() } else { - for (;I != J && Size < 1024; I++) + for (;I != J && Size < MaxArgBytes; I++) { Args[n++] = I->Pkg.Name(); Size += strlen(Args[n-1]); @@ -257,22 +448,25 @@ bool pkgDPkgPM::Go() if (chdir(_config->FindDir("DPkg::Run-Directory","/").c_str()) != 0) _exit(100); - int Flags,dummy; - if ((Flags = fcntl(STDIN_FILENO,F_GETFL,dummy)) < 0) - _exit(100); - - // Discard everything in stdin before forking dpkg - if (fcntl(STDIN_FILENO,F_SETFL,Flags | O_NONBLOCK) < 0) - _exit(100); - - while (read(STDIN_FILENO,&dummy,1) == 1); + if (_config->FindB("DPkg::FlushSTDIN",true) == true) + { + int Flags,dummy; + if ((Flags = fcntl(STDIN_FILENO,F_GETFL,dummy)) < 0) + _exit(100); + + // Discard everything in stdin before forking dpkg + if (fcntl(STDIN_FILENO,F_SETFL,Flags | O_NONBLOCK) < 0) + _exit(100); + + while (read(STDIN_FILENO,&dummy,1) == 1); + + if (fcntl(STDIN_FILENO,F_SETFL,Flags & (~(long)O_NONBLOCK)) < 0) + _exit(100); + } - 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 */ - setenv("DPKG_NO_TSTP","yes",1); + putenv("DPKG_NO_TSTP=yes"); execvp(Args[0],(char **)Args); cerr << "Could not exec dpkg!" << endl; _exit(100); @@ -297,12 +491,12 @@ bool pkgDPkgPM::Go() { RunScripts("DPkg::Post-Invoke"); if (WIFSIGNALED(Status) != 0 && WTERMSIG(Status) == SIGSEGV) - return _error->Error("Sub-process recieved a segmentation fault."); - + return _error->Error("Sub-process %s received a segmentation fault.",Args[0]); + if (WIFEXITED(Status) != 0) - return _error->Error("Sub-process returned an error code (%u)",WEXITSTATUS(Status)); + return _error->Error("Sub-process %s returned an error code (%u)",Args[0],WEXITSTATUS(Status)); - return _error->Error("Sub-process exited unexpectedly"); + return _error->Error("Sub-process %s exited unexpectedly",Args[0]); } }