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