"Fossies" - the Fresh Open Source Software Archive

Member "apt-1.8.2/apt-pkg/deb/debsystem.cc" (28 May 2019, 14563 Bytes) of package /linux/misc/apt-1.8.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "debsystem.cc" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.8.1_vs_1.8.2.

    1 // -*- mode: cpp; mode: fold -*-
    2 // Description                              /*{{{*/
    3 /* ######################################################################
    4 
    5    System - Abstraction for running on different systems.
    6 
    7    Basic general structure..
    8    
    9    ##################################################################### */
   10                                     /*}}}*/
   11 // Include Files                            /*{{{*/
   12 #include <config.h>
   13 
   14 #include <apt-pkg/configuration.h>
   15 #include <apt-pkg/debindexfile.h>
   16 #include <apt-pkg/debsystem.h>
   17 #include <apt-pkg/debversion.h>
   18 #include <apt-pkg/dpkgpm.h>
   19 #include <apt-pkg/error.h>
   20 #include <apt-pkg/fileutl.h>
   21 #include <apt-pkg/pkgcache.h>
   22 
   23 #include <algorithm>
   24 
   25 #include <string>
   26 #include <vector>
   27 #include <ctype.h>
   28 #include <dirent.h>
   29 #include <errno.h>
   30 #include <fcntl.h>
   31 #include <stdlib.h>
   32 #include <string.h>
   33 #include <sys/stat.h>
   34 #include <sys/types.h>
   35 #include <sys/wait.h>
   36 #include <unistd.h>
   37 
   38 #include <apti18n.h>
   39                                     /*}}}*/
   40 
   41 using std::string;
   42 
   43 debSystem debSys;
   44 
   45 class APT_HIDDEN debSystemPrivate {
   46 public:
   47    debSystemPrivate() : FrontendLockFD(-1), LockFD(-1), LockCount(0), StatusFile(0)
   48    {
   49    }
   50    // For locking support
   51    int FrontendLockFD;
   52    int LockFD;
   53    unsigned LockCount;
   54    
   55    debStatusIndex *StatusFile;
   56 };
   57 
   58 // System::debSystem - Constructor                  /*{{{*/
   59 // ---------------------------------------------------------------------
   60 /* */
   61 debSystem::debSystem() : pkgSystem("Debian dpkg interface", &debVS), d(new debSystemPrivate())
   62 {
   63 }
   64                                     /*}}}*/
   65 // System::~debSystem - Destructor                  /*{{{*/
   66 // ---------------------------------------------------------------------
   67 /* */
   68 debSystem::~debSystem()
   69 {
   70    delete d->StatusFile;
   71    delete d;
   72 }
   73                                     /*}}}*/
   74 // System::Lock - Get the lock                      /*{{{*/
   75 // ---------------------------------------------------------------------
   76 /* This mirrors the operations dpkg does when it starts up. Note the
   77    checking of the updates directory. */
   78 bool debSystem::Lock()
   79 {
   80    // Disable file locking
   81    if (_config->FindB("Debug::NoLocking",false) == true || d->LockCount > 0)
   82    {
   83       d->LockCount++;
   84       return true;
   85    }
   86 
   87    // Create the lockfile
   88    string AdminDir = flNotFile(_config->FindFile("Dir::State::status"));
   89    string FrontendLockFile = AdminDir + "lock-frontend";
   90    d->FrontendLockFD = GetLock(FrontendLockFile);
   91    if (d->FrontendLockFD == -1)
   92    {
   93       if (errno == EACCES || errno == EAGAIN)
   94      return _error->Error(_("Unable to acquire the dpkg frontend lock (%s), "
   95                             "is another process using it?"),FrontendLockFile.c_str());
   96       else
   97      return _error->Error(_("Unable to acquire the dpkg frontend lock (%s), "
   98                             "are you root?"),FrontendLockFile.c_str());
   99    }
  100    if (LockInner() == false)
  101    {
  102       close(d->FrontendLockFD);
  103       return false;
  104    }
  105    
  106    // See if we need to abort with a dirty journal
  107    if (CheckUpdates() == true)
  108    {
  109       close(d->LockFD);
  110       close(d->FrontendLockFD);
  111       d->FrontendLockFD = -1;
  112       d->LockFD = -1;
  113       const char *cmd;
  114       if (getenv("SUDO_USER") != NULL)
  115      cmd = "sudo dpkg --configure -a";
  116       else
  117      cmd = "dpkg --configure -a";
  118       // TRANSLATORS: the %s contains the recovery command, usually
  119       //              dpkg --configure -a
  120       return _error->Error(_("dpkg was interrupted, you must manually "
  121                              "run '%s' to correct the problem. "), cmd);
  122    }
  123 
  124      d->LockCount++;
  125       
  126    return true;
  127 }
  128 
  129 bool debSystem::LockInner() {
  130    string AdminDir = flNotFile(_config->FindFile("Dir::State::status"));
  131    d->LockFD = GetLock(AdminDir + "lock");
  132    if (d->LockFD == -1)
  133    {
  134       if (errno == EACCES || errno == EAGAIN)
  135      return _error->Error(_("Unable to lock the administration directory (%s), "
  136                             "is another process using it?"),AdminDir.c_str());
  137       else
  138      return _error->Error(_("Unable to lock the administration directory (%s), "
  139                             "are you root?"),AdminDir.c_str());
  140    }
  141    return true;
  142 }
  143                                     /*}}}*/
  144 // System::UnLock - Drop a lock                     /*{{{*/
  145 // ---------------------------------------------------------------------
  146 /* */
  147 bool debSystem::UnLock(bool NoErrors)
  148 {
  149    if (d->LockCount == 0 && NoErrors == true)
  150       return false;
  151    
  152    if (d->LockCount < 1)
  153       return _error->Error(_("Not locked"));
  154    if (--d->LockCount == 0)
  155    {
  156       close(d->LockFD);
  157       close(d->FrontendLockFD);
  158       d->LockCount = 0;
  159    }
  160    
  161    return true;
  162 }
  163 bool debSystem::UnLockInner(bool NoErrors) {
  164    (void) NoErrors;
  165    close(d->LockFD);
  166    return true;
  167 }
  168                                     /*}}}*/
  169 // System::IsLocked - Check if system is locked                     /*{{{*/
  170 // ---------------------------------------------------------------------
  171 /* This checks if the frontend lock is hold. The inner lock might be
  172  * released. */
  173 bool debSystem::IsLocked()
  174 {
  175    return d->LockCount > 0;
  176 }
  177                                     /*}}}*/
  178 // System::CheckUpdates - Check if the updates dir is dirty     /*{{{*/
  179 // ---------------------------------------------------------------------
  180 /* This does a check of the updates directory (dpkg journal) to see if it has 
  181    any entries in it. */
  182 bool debSystem::CheckUpdates()
  183 {
  184    // Check for updates.. (dirty)
  185    string File = flNotFile(_config->FindFile("Dir::State::status")) + "updates/";
  186    DIR *DirP = opendir(File.c_str());
  187    if (DirP == 0)
  188       return false;
  189    
  190    /* We ignore any files that are not all digits, this skips .,.. and 
  191       some tmp files dpkg will leave behind.. */
  192    bool Damaged = false;
  193    for (struct dirent *Ent = readdir(DirP); Ent != 0; Ent = readdir(DirP))
  194    {
  195       Damaged = true;
  196       for (unsigned int I = 0; Ent->d_name[I] != 0; I++)
  197       {
  198      // Check if its not a digit..
  199      if (isdigit(Ent->d_name[I]) == 0)
  200      {
  201         Damaged = false;
  202         break;
  203      }
  204       }
  205       if (Damaged == true)
  206      break;
  207    }
  208    closedir(DirP);
  209 
  210    return Damaged;
  211 }
  212                                     /*}}}*/
  213 // System::CreatePM - Create the underlying package manager     /*{{{*/
  214 // ---------------------------------------------------------------------
  215 /* */
  216 pkgPackageManager *debSystem::CreatePM(pkgDepCache *Cache) const
  217 {
  218    return new pkgDPkgPM(Cache);
  219 }
  220                                     /*}}}*/
  221 // System::Initialize - Setup the configuration space..         /*{{{*/
  222 // ---------------------------------------------------------------------
  223 /* These are the Debian specific configuration variables.. */
  224 static std::string getDpkgStatusLocation(Configuration const &Cnf) {
  225    Configuration PathCnf;
  226    PathCnf.Set("Dir", Cnf.Find("Dir", "/"));
  227    PathCnf.Set("Dir::State::status", "status");
  228    auto const cnfstatedir = Cnf.Find("Dir::State", STATE_DIR + 1);
  229    // if the state dir ends in apt, replace it with dpkg -
  230    // for the default this gives us the same as the fallback below.
  231    // This can't be a ../dpkg as that would play bad with symlinks
  232    std::string statedir;
  233    if (APT::String::Endswith(cnfstatedir, "/apt/"))
  234       statedir.assign(cnfstatedir, 0, cnfstatedir.length() - 5);
  235    else if (APT::String::Endswith(cnfstatedir, "/apt"))
  236       statedir.assign(cnfstatedir, 0, cnfstatedir.length() - 4);
  237    if (statedir.empty())
  238       PathCnf.Set("Dir::State", "var/lib/dpkg");
  239    else
  240       PathCnf.Set("Dir::State", flCombine(statedir, "dpkg"));
  241    return PathCnf.FindFile("Dir::State::status");
  242 }
  243 bool debSystem::Initialize(Configuration &Cnf)
  244 {
  245    /* These really should be jammed into a generic 'Local Database' engine
  246       which is yet to be determined. The functions in pkgcachegen should
  247       be the only users of these */
  248    Cnf.CndSet("Dir::State::extended_states", "extended_states");
  249    if (Cnf.Exists("Dir::State::status") == false)
  250       Cnf.Set("Dir::State::status", getDpkgStatusLocation(Cnf));
  251    Cnf.CndSet("Dir::Bin::dpkg",BIN_DIR"/dpkg");
  252 
  253    if (d->StatusFile) {
  254      delete d->StatusFile;
  255      d->StatusFile = 0;
  256    }
  257 
  258    return true;
  259 }
  260                                     /*}}}*/
  261 // System::ArchiveSupported - Is a file format supported        /*{{{*/
  262 // ---------------------------------------------------------------------
  263 /* The standard name for a deb is 'deb'.. There are no separate versions
  264    of .deb to worry about.. */
  265 APT_PURE bool debSystem::ArchiveSupported(const char *Type)
  266 {
  267    if (strcmp(Type,"deb") == 0)
  268       return true;
  269    return false;
  270 }
  271                                     /*}}}*/
  272 // System::Score - Determine how 'Debiany' this sys is..        /*{{{*/
  273 // ---------------------------------------------------------------------
  274 /* We check some files that are sure tell signs of this being a Debian
  275    System.. */
  276 signed debSystem::Score(Configuration const &Cnf)
  277 {
  278    signed Score = 0;
  279    if (FileExists(Cnf.FindFile("Dir::State::status",getDpkgStatusLocation(Cnf).c_str())) == true)
  280        Score += 10;
  281    if (FileExists(Cnf.Find("Dir::Bin::dpkg",BIN_DIR"/dpkg")) == true)
  282       Score += 10;
  283    if (FileExists("/etc/debian_version") == true)
  284       Score += 10;
  285    return Score;
  286 }
  287                                     /*}}}*/
  288 // System::AddStatusFiles - Register the status files           /*{{{*/
  289 // ---------------------------------------------------------------------
  290 /* */
  291 bool debSystem::AddStatusFiles(std::vector<pkgIndexFile *> &List)
  292 {
  293    if (d->StatusFile == 0)
  294       d->StatusFile = new debStatusIndex(_config->FindFile("Dir::State::status"));
  295    List.push_back(d->StatusFile);
  296    return true;
  297 }
  298                                     /*}}}*/
  299 // System::FindIndex - Get an index file for status files       /*{{{*/
  300 // ---------------------------------------------------------------------
  301 /* */
  302 bool debSystem::FindIndex(pkgCache::PkgFileIterator File,
  303               pkgIndexFile *&Found) const
  304 {
  305    if (d->StatusFile == 0)
  306       return false;
  307    if (d->StatusFile->FindInCache(*File.Cache()) == File)
  308    {
  309       Found = d->StatusFile;
  310       return true;
  311    }
  312    
  313    return false;
  314 }
  315                                     /*}}}*/
  316 
  317 std::string debSystem::GetDpkgExecutable()              /*{{{*/
  318 {
  319    string Tmp = _config->Find("Dir::Bin::dpkg","dpkg");
  320    string const dpkgChrootDir = _config->FindDir("DPkg::Chroot-Directory", "/");
  321    size_t dpkgChrootLen = dpkgChrootDir.length();
  322    if (dpkgChrootDir != "/" && Tmp.find(dpkgChrootDir) == 0)
  323    {
  324       if (dpkgChrootDir[dpkgChrootLen - 1] == '/')
  325          --dpkgChrootLen;
  326       Tmp = Tmp.substr(dpkgChrootLen);
  327    }
  328    return Tmp;
  329 }
  330                                     /*}}}*/
  331 std::vector<std::string> debSystem::GetDpkgBaseCommand()        /*{{{*/
  332 {
  333    // Generate the base argument list for dpkg
  334    std::vector<std::string> Args = { GetDpkgExecutable() };
  335    // Stick in any custom dpkg options
  336    Configuration::Item const *Opts = _config->Tree("DPkg::Options");
  337    if (Opts != 0)
  338    {
  339       Opts = Opts->Child;
  340       for (; Opts != 0; Opts = Opts->Next)
  341       {
  342      if (Opts->Value.empty() == true)
  343         continue;
  344      Args.push_back(Opts->Value);
  345       }
  346    }
  347    return Args;
  348 }
  349                                     /*}}}*/
  350 void debSystem::DpkgChrootDirectory()                   /*{{{*/
  351 {
  352    std::string const chrootDir = _config->FindDir("DPkg::Chroot-Directory");
  353    if (chrootDir == "/")
  354       return;
  355    std::cerr << "Chrooting into " << chrootDir << std::endl;
  356    if (chroot(chrootDir.c_str()) != 0)
  357       _exit(100);
  358    if (chdir("/") != 0)
  359       _exit(100);
  360 }
  361                                     /*}}}*/
  362 pid_t debSystem::ExecDpkg(std::vector<std::string> const &sArgs, int * const inputFd, int * const outputFd, bool const DiscardOutput)/*{{{*/
  363 {
  364    std::vector<const char *> Args(sArgs.size(), NULL);
  365    std::transform(sArgs.begin(), sArgs.end(), Args.begin(), [](std::string const &s) { return s.c_str(); });
  366    Args.push_back(NULL);
  367 
  368    int external[2] = {-1, -1};
  369    if (inputFd != nullptr || outputFd != nullptr)
  370       if (pipe(external) != 0)
  371       {
  372      _error->WarningE("dpkg", "Can't create IPC pipe for dpkg call");
  373      return -1;
  374       }
  375 
  376    pid_t const dpkg = ExecFork();
  377    if (dpkg == 0) {
  378       int const nullfd = open("/dev/null", O_RDONLY);
  379       if (inputFd == nullptr)
  380      dup2(nullfd, STDIN_FILENO);
  381       else
  382       {
  383      close(external[1]);
  384      dup2(external[0], STDIN_FILENO);
  385       }
  386       if (outputFd == nullptr)
  387      dup2(nullfd, STDOUT_FILENO);
  388       else
  389       {
  390      close(external[0]);
  391      dup2(external[1], STDOUT_FILENO);
  392       }
  393       if (DiscardOutput == true)
  394      dup2(nullfd, STDERR_FILENO);
  395       debSystem::DpkgChrootDirectory();
  396 
  397       if (_system != nullptr && _system->IsLocked() == true)
  398       {
  399      setenv("DPKG_FRONTEND_LOCKED", "true", 1);
  400       }
  401 
  402       if (_config->Find("DPkg::Path", "").empty() == false)
  403      setenv("PATH", _config->Find("DPkg::Path", "").c_str(), 1);
  404 
  405       execvp(Args[0], (char**) &Args[0]);
  406       _error->WarningE("dpkg", "Can't execute dpkg!");
  407       _exit(100);
  408    }
  409    if (outputFd != nullptr)
  410    {
  411       close(external[1]);
  412       *outputFd = external[0];
  413    }
  414    else if (inputFd != nullptr)
  415    {
  416       close(external[0]);
  417       *inputFd = external[1];
  418    }
  419    return dpkg;
  420 }
  421                                     /*}}}*/
  422 bool debSystem::SupportsMultiArch()                 /*{{{*/
  423 {
  424    std::vector<std::string> Args = GetDpkgBaseCommand();
  425    Args.push_back("--assert-multi-arch");
  426    pid_t const dpkgAssertMultiArch = ExecDpkg(Args, nullptr, nullptr, true);
  427    if (dpkgAssertMultiArch > 0)
  428    {
  429       int Status = 0;
  430       while (waitpid(dpkgAssertMultiArch, &Status, 0) != dpkgAssertMultiArch)
  431       {
  432      if (errno == EINTR)
  433         continue;
  434      _error->WarningE("dpkgGo", _("Waited for %s but it wasn't there"), "dpkg --assert-multi-arch");
  435      break;
  436       }
  437       if (WIFEXITED(Status) == true && WEXITSTATUS(Status) == 0)
  438      return true;
  439    }
  440    return false;
  441 }
  442                                     /*}}}*/
  443 std::vector<std::string> debSystem::SupportedArchitectures()        /*{{{*/
  444 {
  445    std::vector<std::string> archs;
  446    {
  447       string const arch = _config->Find("APT::Architecture");
  448       if (arch.empty() == false)
  449      archs.push_back(std::move(arch));
  450    }
  451 
  452    std::vector<std::string> sArgs = GetDpkgBaseCommand();
  453    sArgs.push_back("--print-foreign-architectures");
  454    int outputFd = -1;
  455    pid_t const dpkgMultiArch = ExecDpkg(sArgs, nullptr, &outputFd, true);
  456    if (dpkgMultiArch == -1)
  457       return archs;
  458 
  459    FILE *dpkg = fdopen(outputFd, "r");
  460    if(dpkg != NULL) {
  461       char* buf = NULL;
  462       size_t bufsize = 0;
  463       while (getline(&buf, &bufsize, dpkg) != -1)
  464       {
  465      char* tok_saveptr;
  466      char* arch = strtok_r(buf, " ", &tok_saveptr);
  467      while (arch != NULL) {
  468         for (; isspace_ascii(*arch) != 0; ++arch);
  469         if (arch[0] != '\0') {
  470            char const* archend = arch;
  471            for (; isspace_ascii(*archend) == 0 && *archend != '\0'; ++archend);
  472            string a(arch, (archend - arch));
  473            if (std::find(archs.begin(), archs.end(), a) == archs.end())
  474           archs.push_back(a);
  475         }
  476         arch = strtok_r(NULL, " ", &tok_saveptr);
  477      }
  478       }
  479       free(buf);
  480       fclose(dpkg);
  481    }
  482    ExecWait(dpkgMultiArch, "dpkg --print-foreign-architectures", true);
  483    return archs;
  484 }
  485                                     /*}}}*/