apt  2.2.4
About: Apt (Advanced Package Tool) is a management system for software packages (Debian/Ubuntu). Release series 2.2.
  Fossies Dox: apt-2.2.4.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

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