diff options
Diffstat (limited to 'apt-pkg/deb/dpkgpm.cc')
-rw-r--r-- | apt-pkg/deb/dpkgpm.cc | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/apt-pkg/deb/dpkgpm.cc b/apt-pkg/deb/dpkgpm.cc new file mode 100644 index 000000000..75a5c77be --- /dev/null +++ b/apt-pkg/deb/dpkgpm.cc @@ -0,0 +1,197 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: dpkgpm.cc,v 1.1 1998/11/13 04:23:39 jgg Exp $ +/* ###################################################################### + + DPKG Package Manager - Provide an interface to dpkg + + ##################################################################### */ + /*}}}*/ +// Includes /*{{{*/ +#ifdef __GNUG__ +#pragma implementation "apt-pkg/dpkgpm.h" +#endif +#include <apt-pkg/dpkgpm.h> +#include <apt-pkg/error.h> +#include <apt-pkg/configuration.h> + +#include <unistd.h> +#include <stdlib.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <signal.h> +#include <errno.h> + /*}}}*/ + +// DPkgPM::pkgDPkgPM - Constructor /*{{{*/ +// --------------------------------------------------------------------- +/* */ +pkgDPkgPM::pkgDPkgPM(pkgDepCache &Cache) : pkgPackageManager(Cache) +{ +} + /*}}}*/ +// DPkgPM::pkgDPkgPM - Destructor /*{{{*/ +// --------------------------------------------------------------------- +/* */ +pkgDPkgPM::~pkgDPkgPM() +{ +} + /*}}}*/ +// DPkgPM::Install - Install a package /*{{{*/ +// --------------------------------------------------------------------- +/* Add an install operation to the sequence list */ +bool pkgDPkgPM::Install(PkgIterator Pkg,string File) +{ + if (File.empty() == true || Pkg.end() == true) + return _error->Error("Internal Error, No file name for %s",Pkg.Name()); + + List.push_back(Item(Item::Install,Pkg,File)); + return true; +} + /*}}}*/ +// DPkgPM::Configure - Configure a package /*{{{*/ +// --------------------------------------------------------------------- +/* Add a configure operation to the sequence list */ +bool pkgDPkgPM::Configure(PkgIterator Pkg) +{ + if (Pkg.end() == true) + return false; + + List.push_back(Item(Item::Configure,Pkg)); + return true; +} + /*}}}*/ +// DPkgPM::Remove - Remove a package /*{{{*/ +// --------------------------------------------------------------------- +/* Add a remove operation to the sequence list */ +bool pkgDPkgPM::Remove(PkgIterator Pkg) +{ + if (Pkg.end() == true) + return false; + + List.push_back(Item(Item::Remove,Pkg)); + return true; +} + /*}}}*/ +// DPkgPM::Go - Run the sequence /*{{{*/ +// --------------------------------------------------------------------- +/* This globs the operations and calls dpkg */ +bool pkgDPkgPM::Go() +{ + for (vector<Item>::iterator I = List.begin(); I != List.end();) + { + vector<Item>::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; + + int n= 0; + Args[n++] = "dpkg"; + + switch (I->Op) + { + case Item::Remove: + Args[n++] = "--force-depends"; + Args[n++] = "--force-remove-essential"; + Args[n++] = "--remove"; + break; + + case Item::Configure: + Args[n++] = "--configure"; + break; + + case Item::Install: + Args[n++] = "--unpack"; + break; + } + + // Write in the file or package names + if (I->Op == Item::Install) + for (;I != J; I++) + Args[n++] = I->File.c_str(); + else + for (;I != J; I++) + Args[n++] = I->Pkg.Name(); + Args[n] = 0; + +/* for (int k = 0; k != n; k++) + cout << Args[k] << ' '; + cout << endl;*/ + + cout << flush; + clog << flush; + cerr << flush; + + /* Mask off sig int/quit. We do this because dpkg also does when + it forks scripts. What happens is that when you hit ctrl-c it sends + it to all processes in the group. Since dpkg ignores the signal + it doesn't die but we do! So we must also ignore it */ + signal(SIGQUIT,SIG_IGN); + signal(SIGINT,SIG_IGN); + + // Fork dpkg + pid_t Child = fork(); + if (Child < 0) + return _error->Errno("fork","Could't fork"); + + // This is the child + if (Child == 0) + { + signal(SIGQUIT,SIG_DFL); + signal(SIGINT,SIG_DFL); + signal(SIGWINCH,SIG_DFL); + signal(SIGCONT,SIG_DFL); + signal(SIGTSTP,SIG_DFL); + + if (chdir(_config->FindDir("Dir::Cache::Archives").c_str()) != 0) + exit(100); + + // Close all of our FDs - just in case + for (int K = 3; K != 40; K++) + fcntl(K,F_SETFD,FD_CLOEXEC); + + 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); + + /* No Job Control Stop Env is a magic dpkg var that prevents it + from using sigstop */ + setenv("DPKG_NO_TSTP","yes",1); + execvp("dpkg",(char **)Args); + cerr << "Could not exec dpkg!" << endl; + exit(100); + } + + // Wait for dpkg + int Status = 0; + while (waitpid(Child,&Status,0) != Child) + { + if (errno == EINTR) + continue; + return _error->Errno("waitpid","Couldn't wait for subprocess"); + } + + // Check for an error code. + if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0) + return _error->Error("Sub-process returned an error code"); + + // Restore sig int/quit + signal(SIGQUIT,SIG_DFL); + signal(SIGINT,SIG_DFL); + } + return true; +} + /*}}}*/ |