X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/1a22e16a1ebf08243c1836e1c593cb966cae4850..463c8d801595ce5ac94d7c032264820be7434232:/cmdline/apt-get.cc diff --git a/cmdline/apt-get.cc b/cmdline/apt-get.cc index 2370318e8..500a0a3c5 100644 --- a/cmdline/apt-get.cc +++ b/cmdline/apt-get.cc @@ -15,7 +15,7 @@ upgrade - Smart-Download the newest versions of all packages dselect-upgrade - Follows dselect's changes to the Status: field and installes new and removes old packages - dist-upgrade - Powerfull upgrader designed to handle the issues with + dist-upgrade - Powerful upgrader designed to handle the issues with a new distribution. install - Download and install a given package (by name, not by .deb) check - Update the package cache and check for broken packages @@ -27,64 +27,69 @@ // Include Files /*{{{*/ #include +#include +#include #include -#include +#include +#include +#include #include -#include +#include #include -#include -#include -#include -#include +#include #include -#include -#include -#include -#include -#include -#include +#include +#include +#include #include -#include -#include -#include +#include #include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include -#include -#include +#include +#include +#include +#include #include #include -#include +#include +#include #include -#include #include -#include -#include +#include #include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include +#include #include -#include +#include #include -#include -#include +#include +#include +#include +#include #include +#include +#include +#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include /*}}}*/ @@ -95,7 +100,7 @@ using namespace std; // --------------------------------------------------------------------- /* This used to be inlined in DoInstall, but with the advent of regex package name matching it was split out.. */ -bool TryToInstallBuildDep(pkgCache::PkgIterator Pkg,pkgCacheFile &Cache, +static bool TryToInstallBuildDep(pkgCache::PkgIterator Pkg,pkgCacheFile &Cache, pkgProblemResolver &Fix,bool Remove,bool BrokenFix, bool AllowFail = true) { @@ -132,25 +137,73 @@ bool TryToInstallBuildDep(pkgCache::PkgIterator Pkg,pkgCacheFile &Cache, return true; } /*}}}*/ +// GetReleaseForSourceRecord - Return Suite for the given srcrecord /*{{{*/ +// --------------------------------------------------------------------- +/* */ +static std::string GetReleaseForSourceRecord(pkgSourceList *SrcList, + pkgSrcRecords::Parser *Parse) +{ + // try to find release + const pkgIndexFile& CurrentIndexFile = Parse->Index(); + + for (pkgSourceList::const_iterator S = SrcList->begin(); + S != SrcList->end(); ++S) + { + vector *Indexes = (*S)->GetIndexFiles(); + for (vector::const_iterator IF = Indexes->begin(); + IF != Indexes->end(); ++IF) + { + if (&CurrentIndexFile == (*IF)) + { + std::string const path = (*S)->LocalFileName(); + if (path != "") + { + indexRecords records; + records.Load(path); + return records.GetSuite(); + } + } + } + } + return ""; +} + /*}}}*/ // FindSrc - Find a source record /*{{{*/ // --------------------------------------------------------------------- /* */ -pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs, +#if APT_PKG_ABI >= 413 +static pkgSrcRecords::Parser *FindSrc(const char *Name, +#else +static pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs, +#endif pkgSrcRecords &SrcRecs,string &Src, CacheFile &CacheFile) { - string VerTag; - string DefRel = _config->Find("APT::Default-Release"); + string VerTag, UserRequestedVerTag; + string ArchTag = ""; + string RelTag = _config->Find("APT::Default-Release"); string TmpSrc = Name; pkgDepCache *Cache = CacheFile.GetDepCache(); - // extract the version/release from the pkgname - const size_t found = TmpSrc.find_last_of("/="); - if (found != string::npos) { - if (TmpSrc[found] == '/') - DefRel = TmpSrc.substr(found+1); - else - VerTag = TmpSrc.substr(found+1); + // extract release + size_t found = TmpSrc.find_last_of("/"); + if (found != string::npos) + { + RelTag = TmpSrc.substr(found+1); + TmpSrc = TmpSrc.substr(0,found); + } + // extract the version + found = TmpSrc.find_last_of("="); + if (found != string::npos) + { + VerTag = UserRequestedVerTag = TmpSrc.substr(found+1); + TmpSrc = TmpSrc.substr(0,found); + } + // extract arch + found = TmpSrc.find_last_of(":"); + if (found != string::npos) + { + ArchTag = TmpSrc.substr(found+1); TmpSrc = TmpSrc.substr(0,found); } @@ -158,10 +211,25 @@ pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs, install a version and determine the source package name, then look in the archive for a source package of the same name. */ bool MatchSrcOnly = _config->FindB("APT::Get::Only-Source"); - const pkgCache::PkgIterator Pkg = Cache->FindPkg(TmpSrc); + pkgCache::PkgIterator Pkg; + if (ArchTag != "") + Pkg = Cache->FindPkg(TmpSrc, ArchTag); + else + Pkg = Cache->FindPkg(TmpSrc); + + // if we can't find a package but the user qualified with a arch, + // error out here + if (Pkg.end() && ArchTag != "") + { + Src = Name; + _error->Error(_("Can not find a package for architecture '%s'"), + ArchTag.c_str()); + return 0; + } + if (MatchSrcOnly == false && Pkg.end() == false) { - if(VerTag.empty() == false || DefRel.empty() == false) + if(VerTag != "" || RelTag != "" || ArchTag != "") { bool fuzzy = false; // we have a default release, try to locate the pkg. we do it like @@ -181,6 +249,17 @@ pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs, if (Ver.end() == true) break; } + + // ignore arches that are not for us + if (ArchTag != "" && Ver.Arch() != ArchTag) + continue; + + // pick highest version for the arch unless the user wants + // something else + if (ArchTag != "" && VerTag == "" && RelTag == "") + if(Cache->VS().CmpVersion(VerTag, Ver.VerStr()) < 0) + VerTag = Ver.VerStr(); + // We match against a concrete version (or a part of this version) if (VerTag.empty() == false && (fuzzy == true || Cache->VS().CmpVersion(VerTag, Ver.VerStr()) != 0) && // exact match @@ -201,55 +280,73 @@ pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs, // or we match against a release if(VerTag.empty() == false || - (VF.File().Archive() != 0 && VF.File().Archive() == DefRel) || - (VF.File().Codename() != 0 && VF.File().Codename() == DefRel)) + (VF.File().Archive() != 0 && VF.File().Archive() == RelTag) || + (VF.File().Codename() != 0 && VF.File().Codename() == RelTag)) { + // the Version we have is possibly fuzzy or includes binUploads, + // so we use the Version of the SourcePkg (empty if same as package) +#if APT_PKG_ABI >= 413 + Src = Ver.SourcePkgName(); + VerTag = Ver.SourceVerStr(); +#else pkgRecords::Parser &Parse = Recs.Lookup(VF); Src = Parse.SourcePkg(); // no SourcePkg name, so it is the "binary" name if (Src.empty() == true) Src = TmpSrc; - // the Version we have is possibly fuzzy or includes binUploads, - // so we use the Version of the SourcePkg (empty if same as package) VerTag = Parse.SourceVer(); if (VerTag.empty() == true) VerTag = Ver.VerStr(); +#endif break; } } if (Src.empty() == false) break; } -#if 0 - if (Src.empty() == true) - { - // Sources files have no codename information - if (VerTag.empty() == true && DefRel.empty() == false) - { - _error->Warning(_("Ignore unavailable target release '%s' of package '%s'"), DefRel.c_str(), TmpSrc.c_str()); - return 0; - } - } -#endif } + + if (Src == "" && ArchTag != "") + { + if (VerTag != "") + _error->Error(_("Can not find a package '%s' with version '%s'"), + Pkg.FullName().c_str(), VerTag.c_str()); + if (RelTag != "") + _error->Error(_("Can not find a package '%s' with release '%s'"), + Pkg.FullName().c_str(), RelTag.c_str()); + Src = Name; + return 0; + } + + if (Src.empty() == true) { // if we don't have found a fitting package yet so we will // choose a good candidate and proceed with that. // Maybe we will find a source later on with the right VerTag + // or RelTag pkgCache::VerIterator Ver = Cache->GetCandidateVer(Pkg); if (Ver.end() == false) { +#if APT_PKG_ABI >= 413 + if (strcmp(Ver.SourcePkgName(),Ver.ParentPkg().Name()) != 0) + Src = Ver.SourcePkgName(); + if (VerTag.empty() == true && strcmp(Ver.SourceVerStr(),Ver.VerStr()) != 0) + VerTag = Ver.SourceVerStr(); +#else pkgRecords::Parser &Parse = Recs.Lookup(Ver.FileList()); Src = Parse.SourcePkg(); if (VerTag.empty() == true) VerTag = Parse.SourceVer(); +#endif } } } if (Src.empty() == true) + { Src = TmpSrc; + } else { /* if we have a source pkg name, make sure to only search @@ -267,7 +364,7 @@ pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs, pkgSrcRecords::Parser *Last = 0; unsigned long Offset = 0; string Version; - string FoundRel; + pkgSourceList *SrcList = CacheFile.GetSourceList(); /* Iterate over all of the hits, which includes the resulting binary packages in the search */ @@ -279,38 +376,18 @@ pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs, { const string Ver = Parse->Version(); - - // find release - const pkgIndexFile& SI = Parse->Index(); - pkgSourceList *SrcList = CacheFile.GetSourceList(); - for (pkgSourceList::const_iterator S = SrcList->begin(); - S != SrcList->end(); ++S) + // See if we need to look for a specific release tag + if (RelTag != "" && UserRequestedVerTag == "") { - vector *Indexes = (*S)->GetIndexFiles(); - for (vector::const_iterator IF = Indexes->begin(); - IF != Indexes->end(); ++IF) + const string Rel = GetReleaseForSourceRecord(SrcList, Parse); + + if (Rel == RelTag) { - if (&SI == (*IF)) - { - std::string dirname = _config->FindDir("Dir::State::lists"); - std::string path = dirname + URItoFileName((*S)->GetURI()) + "dists_" + (*S)->GetDist() + "_Release"; - indexRecords records; - records.Load(path); - if (records.GetSuite() == DefRel) - { - ioprintf(clog, "Selectied version '%s' (%s) for %s\n", - Ver.c_str(), DefRel.c_str(), Src.c_str()); - Last = Parse; - Offset = Parse->Offset(); - Version = Ver; - FoundRel = DefRel; - break; - } - } + Last = Parse; + Offset = Parse->Offset(); + Version = Ver; } } - if (DefRel.empty() == false && (DefRel == FoundRel)) - break; // Ignore all versions which doesn't fit if (VerTag.empty() == false && @@ -324,15 +401,18 @@ pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs, Version = Ver; } - // was the version check above an exact match? If so, we don't need to look further + // was the version check above an exact match? + // If so, we don't need to look further if (VerTag.empty() == false && (VerTag == Ver)) - { - std::cerr << "meep" << std::endl; break; - } } + if (UserRequestedVerTag == "" && Version != "" && RelTag != "") + ioprintf(c1out, "Selected version '%s' (%s) for %s\n", + Version.c_str(), RelTag.c_str(), Src.c_str()); + if (Last != 0 || VerTag.empty() == true) break; + _error->Error(_("Can not find version '%s' of package '%s'"), VerTag.c_str(), TmpSrc.c_str()); return 0; } @@ -343,7 +423,7 @@ pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs, } /*}}}*/ /* mark packages as automatically/manually installed. {{{*/ -bool DoMarkAuto(CommandLine &CmdL) +static bool DoMarkAuto(CommandLine &CmdL) { bool Action = true; int AutoMarkChanged = 0; @@ -388,7 +468,7 @@ bool DoMarkAuto(CommandLine &CmdL) // DoDSelectUpgrade - Do an upgrade by following dselects selections /*{{{*/ // --------------------------------------------------------------------- /* Follows dselect's selections */ -bool DoDSelectUpgrade(CommandLine &CmdL) +static bool DoDSelectUpgrade(CommandLine &) { CacheFile Cache; if (Cache.OpenForInstall() == false || Cache.CheckDeps() == false) @@ -426,7 +506,7 @@ bool DoDSelectUpgrade(CommandLine &CmdL) } /* Resolve any problems that dselect created, allupgrade cannot handle - such things. We do so quite agressively too.. */ + such things. We do so quite aggressively too.. */ if (Cache->BrokenCount() != 0) { pkgProblemResolver Fix(Cache); @@ -452,7 +532,7 @@ bool DoDSelectUpgrade(CommandLine &CmdL) } // Now upgrade everything - if (pkgAllUpgrade(Cache) == false) + if (APT::Upgrade::Upgrade(Cache, APT::Upgrade::FORBID_REMOVE_PACKAGES | APT::Upgrade::FORBID_INSTALL_NEW_PACKAGES) == false) { ShowBroken(c1out,Cache,false); return _error->Error(_("Internal error, problem resolver broke stuff")); @@ -464,33 +544,29 @@ bool DoDSelectUpgrade(CommandLine &CmdL) // DoClean - Remove download archives /*{{{*/ // --------------------------------------------------------------------- /* */ -bool DoClean(CommandLine &CmdL) +static bool DoClean(CommandLine &) { std::string const archivedir = _config->FindDir("Dir::Cache::archives"); - std::string const pkgcache = _config->FindFile("Dir::cache::pkgcache"); - std::string const srcpkgcache = _config->FindFile("Dir::cache::srcpkgcache"); + std::string const listsdir = _config->FindDir("Dir::state::lists"); if (_config->FindB("APT::Get::Simulate") == true) { + std::string const pkgcache = _config->FindFile("Dir::cache::pkgcache"); + std::string const srcpkgcache = _config->FindFile("Dir::cache::srcpkgcache"); cout << "Del " << archivedir << "* " << archivedir << "partial/*"<< endl + << "Del " << listsdir << "partial/*" << endl << "Del " << pkgcache << " " << srcpkgcache << endl; return true; } - - // Lock the archive directory - FileFd Lock; - if (_config->FindB("Debug::NoLocking",false) == false) - { - int lock_fd = GetLock(archivedir + "lock"); - if (lock_fd < 0) - return _error->Error(_("Unable to lock the download directory")); - Lock.Fd(lock_fd); - } - + pkgAcquire Fetcher; + Fetcher.GetLock(archivedir); Fetcher.Clean(archivedir); Fetcher.Clean(archivedir + "partial/"); + Fetcher.GetLock(listsdir); + Fetcher.Clean(listsdir + "partial/"); + pkgCacheFile::RemoveCaches(); return true; @@ -512,7 +588,7 @@ class LogCleaner : public pkgArchiveCleaner }; }; -bool DoAutoClean(CommandLine &CmdL) +static bool DoAutoClean(CommandLine &) { // Lock the archive directory FileFd Lock; @@ -536,23 +612,21 @@ bool DoAutoClean(CommandLine &CmdL) /*}}}*/ // DoDownload - download a binary /*{{{*/ // --------------------------------------------------------------------- -bool DoDownload(CommandLine &CmdL) +static bool DoDownload(CommandLine &CmdL) { CacheFile Cache; if (Cache.ReadOnlyOpen() == false) return false; - APT::CacheSetHelper helper(c0out); - APT::VersionList verset = APT::VersionList::FromCommandLine(Cache, - CmdL.FileList + 1, APT::VersionList::CANDIDATE, helper); + APT::CacheSetHelper helper; + APT::VersionSet verset = APT::VersionSet::FromCommandLine(Cache, + CmdL.FileList + 1, APT::CacheSetHelper::CANDIDATE, helper); if (verset.empty() == true) return false; - AcqTextStatus Stat(ScreenWidth, _config->FindI("quiet", 0)); - pkgAcquire Fetcher; - if (Fetcher.Setup(&Stat) == false) - return false; + AcqTextStatus Stat(std::cout, ScreenWidth,_config->FindI("quiet",0)); + pkgAcquire Fetcher(&Stat); pkgRecords Recs(Cache); pkgSourceList *SrcList = Cache.GetSourceList(); @@ -563,10 +637,12 @@ bool DoDownload(CommandLine &CmdL) std::string const cwd = SafeGetCWD(); _config->Set("Dir::Cache::Archives", cwd); int i = 0; - for (APT::VersionList::const_iterator Ver = verset.begin(); + for (APT::VersionSet::const_iterator Ver = verset.begin(); Ver != verset.end(); ++Ver, ++i) { pkgAcquire::Item *I = new pkgAcqArchive(&Fetcher, SrcList, &Recs, *Ver, storefile[i]); + if (storefile[i].empty()) + continue; std::string const filename = cwd + flNotDir(storefile[i]); storefile[i].assign(filename); I->DestFile.assign(filename); @@ -577,11 +653,14 @@ bool DoDownload(CommandLine &CmdL) { pkgAcquire::UriIterator I = Fetcher.UriBegin(); for (; I != Fetcher.UriEnd(); ++I) - cout << '\'' << I->URI << "' " << flNotDir(I->Owner->DestFile) << ' ' << + cout << '\'' << I->URI << "' " << flNotDir(I->Owner->DestFile) << ' ' << I->Owner->FileSize << ' ' << I->Owner->HashSum() << endl; return true; } + // Disable drop-privs if "_apt" can not write to the target dir + CheckDropPrivsMustBeDisabled(Fetcher); + if (_error->PendingError() == true || CheckAuth(Fetcher, false) == false) return false; @@ -591,14 +670,17 @@ bool DoDownload(CommandLine &CmdL) // copy files in local sources to the current directory for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); ++I) - if ((*I)->Local == true && (*I)->Status == pkgAcquire::Item::StatDone) + { + std::string const filename = cwd + flNotDir((*I)->DestFile); + if ((*I)->Local == true && + filename != (*I)->DestFile && + (*I)->Status == pkgAcquire::Item::StatDone) { - std::string const filename = cwd + flNotDir((*I)->DestFile); std::ifstream src((*I)->DestFile.c_str(), std::ios::binary); std::ofstream dst(filename.c_str(), std::ios::binary); dst << src.rdbuf(); } - + } return Failed == false; } /*}}}*/ @@ -606,7 +688,7 @@ bool DoDownload(CommandLine &CmdL) // --------------------------------------------------------------------- /* Opening automatically checks the system, this command is mostly used for debugging */ -bool DoCheck(CommandLine &CmdL) +static bool DoCheck(CommandLine &) { CacheFile Cache; Cache.Open(); @@ -625,7 +707,7 @@ struct DscFile string Dsc; }; -bool DoSource(CommandLine &CmdL) +static bool DoSource(CommandLine &CmdL) { CacheFile Cache; if (Cache.Open(false) == false) @@ -640,17 +722,18 @@ bool DoSource(CommandLine &CmdL) pkgSourceList *List = Cache.GetSourceList(); // Create the text record parsers +#if APT_PKG_ABI < 413 pkgRecords Recs(Cache); +#endif pkgSrcRecords SrcRecs(*List); if (_error->PendingError() == true) return false; // Create the download object - AcqTextStatus Stat(ScreenWidth,_config->FindI("quiet",0)); - pkgAcquire Fetcher; - Fetcher.SetLog(&Stat); + AcqTextStatus Stat(std::cout, ScreenWidth,_config->FindI("quiet",0)); + pkgAcquire Fetcher(&Stat); - DscFile *Dsc = new DscFile[CmdL.FileSize()]; + SPtrArray Dsc = new DscFile[CmdL.FileSize()]; // insert all downloaded uris into this set to avoid downloading them // twice @@ -665,15 +748,21 @@ bool DoSource(CommandLine &CmdL) // Load the requestd sources into the fetcher unsigned J = 0; + std::string UntrustedList; for (const char **I = CmdL.FileList + 1; *I != 0; I++, J++) { string Src; +#if APT_PKG_ABI >= 413 + pkgSrcRecords::Parser *Last = FindSrc(*I,SrcRecs,Src,Cache); +#else pkgSrcRecords::Parser *Last = FindSrc(*I,Recs,SrcRecs,Src,Cache); - +#endif if (Last == 0) { - delete[] Dsc; return _error->Error(_("Unable to find a source package for %s"),Src.c_str()); } + + if (Last->Index().IsTrusted() == false) + UntrustedList += Src + " "; string srec = Last->AsStr(); string::size_type pos = srec.find("\nVcs-"); @@ -703,14 +792,13 @@ bool DoSource(CommandLine &CmdL) } // Back track - vector Lst; - if (Last->Files(Lst) == false) { - delete[] Dsc; + vector Lst; + if (Last->Files2(Lst) == false) { return false; } // Load them into the fetcher - for (vector::const_iterator I = Lst.begin(); + for (vector::const_iterator I = Lst.begin(); I != Lst.end(); ++I) { // Try to guess what sort of file it is we are getting. @@ -739,56 +827,36 @@ bool DoSource(CommandLine &CmdL) queued.insert(Last->Index().ArchiveURI(I->Path)); // check if we have a file with that md5 sum already localy - if(!I->MD5Hash.empty() && FileExists(flNotDir(I->Path))) - { - FileFd Fd(flNotDir(I->Path), FileFd::ReadOnly); - MD5Summation sum; - sum.AddFD(Fd.Fd(), Fd.Size()); - Fd.Close(); - if((string)sum.Result() == I->MD5Hash) + std::string localFile = flNotDir(I->Path); + if (FileExists(localFile) == true) + if(I->Hashes.VerifyFile(localFile) == true) { ioprintf(c1out,_("Skipping already downloaded file '%s'\n"), - flNotDir(I->Path).c_str()); + localFile.c_str()); continue; } + + // see if we have a hash (Acquire::ForceHash is the only way to have none) + if (I->Hashes.usable() == false && _config->FindB("APT::Get::AllowUnauthenticated",false) == false) + { + ioprintf(c1out, "Skipping download of file '%s' as requested hashsum is not available for authentication\n", + localFile.c_str()); + continue; } new pkgAcqFile(&Fetcher,Last->Index().ArchiveURI(I->Path), - I->MD5Hash,I->Size, - Last->Index().SourceInfo(*Last,*I),Src); + I->Hashes, I->FileSize, Last->Index().SourceInfo(*Last,*I), Src); } } - + // Display statistics unsigned long long FetchBytes = Fetcher.FetchNeeded(); unsigned long long FetchPBytes = Fetcher.PartialPresent(); unsigned long long DebBytes = Fetcher.TotalNeeded(); - // Check for enough free space - struct statvfs Buf; - string OutputDir = "."; - if (statvfs(OutputDir.c_str(),&Buf) != 0) { - delete[] Dsc; - if (errno == EOVERFLOW) - return _error->WarningE("statvfs",_("Couldn't determine free space in %s"), - OutputDir.c_str()); - else - return _error->Errno("statvfs",_("Couldn't determine free space in %s"), - OutputDir.c_str()); - } else if (unsigned(Buf.f_bfree) < (FetchBytes - FetchPBytes)/Buf.f_bsize) - { - struct statfs Stat; - if (statfs(OutputDir.c_str(),&Stat) != 0 -#if HAVE_STRUCT_STATFS_F_TYPE - || unsigned(Stat.f_type) != RAMFS_MAGIC -#endif - ) { - delete[] Dsc; - return _error->Error(_("You don't have enough free space in %s"), - OutputDir.c_str()); - } - } - + if (CheckFreeSpaceBeforeDownload(".", (FetchBytes - FetchPBytes)) == false) + return false; + // Number of bytes if (DebBytes != FetchBytes) //TRANSLATOR: The required space between number and unit is already included @@ -805,10 +873,9 @@ bool DoSource(CommandLine &CmdL) { for (unsigned I = 0; I != J; I++) ioprintf(cout,_("Fetch source %s\n"),Dsc[I].Package.c_str()); - delete[] Dsc; return true; } - + // Just print out the uris an exit if the --print-uris flag was used if (_config->FindB("APT::Get::Print-URIs") == true) { @@ -816,22 +883,26 @@ bool DoSource(CommandLine &CmdL) for (; I != Fetcher.UriEnd(); ++I) cout << '\'' << I->URI << "' " << flNotDir(I->Owner->DestFile) << ' ' << I->Owner->FileSize << ' ' << I->Owner->HashSum() << endl; - delete[] Dsc; return true; } + // Disable drop-privs if "_apt" can not write to the target dir + CheckDropPrivsMustBeDisabled(Fetcher); + + // check authentication status of the source as well + if (UntrustedList != "" && !AuthPrompt(UntrustedList, false)) + return false; + // Run it bool Failed = false; if (AcquireRun(Fetcher, 0, &Failed, NULL) == false || Failed == true) { - delete[] Dsc; return _error->Error(_("Failed to fetch some archives.")); } if (_config->FindB("APT::Get::Download-only",false) == true) { c1out << _("Download complete and in download only mode") << endl; - delete[] Dsc; return true; } @@ -862,44 +933,50 @@ bool DoSource(CommandLine &CmdL) else { // Call dpkg-source - char S[500]; - snprintf(S,sizeof(S),"%s -x %s", + std::string const sourceopts = _config->Find("DPkg::Source-Options", "-x"); + std::string S; + strprintf(S, "%s %s %s", _config->Find("Dir::Bin::dpkg-source","dpkg-source").c_str(), - Dsc[I].Dsc.c_str()); - if (system(S) != 0) + sourceopts.c_str(), Dsc[I].Dsc.c_str()); + if (system(S.c_str()) != 0) { - fprintf(stderr,_("Unpack command '%s' failed.\n"),S); - fprintf(stderr,_("Check if the 'dpkg-dev' package is installed.\n")); + fprintf(stderr, _("Unpack command '%s' failed.\n"), S.c_str()); + fprintf(stderr, _("Check if the 'dpkg-dev' package is installed.\n")); _exit(1); - } + } } - + // Try to compile it with dpkg-buildpackage if (_config->FindB("APT::Get::Compile",false) == true) { string buildopts = _config->Find("APT::Get::Host-Architecture"); if (buildopts.empty() == false) buildopts = "-a" + buildopts + " "; + + // get all active build profiles + std::string const profiles = APT::Configuration::getBuildProfilesString(); + if (profiles.empty() == false) + buildopts.append(" -P").append(profiles).append(" "); + buildopts.append(_config->Find("DPkg::Build-Options","-b -uc")); // Call dpkg-buildpackage - char S[500]; - snprintf(S,sizeof(S),"cd %s && %s %s", + std::string S; + strprintf(S, "cd %s && %s %s", Dir.c_str(), _config->Find("Dir::Bin::dpkg-buildpackage","dpkg-buildpackage").c_str(), buildopts.c_str()); - - if (system(S) != 0) + + if (system(S.c_str()) != 0) { - fprintf(stderr,_("Build command '%s' failed.\n"),S); + fprintf(stderr, _("Build command '%s' failed.\n"), S.c_str()); _exit(1); - } - } + } + } } - + _exit(0); } - delete[] Dsc; // Wait for the subprocess int Status = 0; @@ -920,7 +997,7 @@ bool DoSource(CommandLine &CmdL) // --------------------------------------------------------------------- /* This function will look at the build depends list of the given source package and install the necessary packages to make it true, or fail. */ -bool DoBuildDep(CommandLine &CmdL) +static bool DoBuildDep(CommandLine &CmdL) { CacheFile Cache; @@ -938,17 +1015,10 @@ bool DoBuildDep(CommandLine &CmdL) pkgSourceList *List = Cache.GetSourceList(); // Create the text record parsers - pkgRecords Recs(Cache); pkgSrcRecords SrcRecs(*List); if (_error->PendingError() == true) return false; - // Create the download object - AcqTextStatus Stat(ScreenWidth,_config->FindI("quiet",0)); - pkgAcquire Fetcher; - if (Fetcher.Setup(&Stat) == false) - return false; - bool StripMultiArch; string hostArch = _config->Find("APT::Get::Host-Architecture"); if (hostArch.empty() == false) @@ -965,7 +1035,40 @@ bool DoBuildDep(CommandLine &CmdL) for (const char **I = CmdL.FileList + 1; *I != 0; I++, J++) { string Src; - pkgSrcRecords::Parser *Last = FindSrc(*I,Recs,SrcRecs,Src,Cache); + pkgSrcRecords::Parser *Last = 0; + SPtr LastOwner; + + // an unpacked debian source tree + using APT::String::Startswith; + if ((Startswith(*I, "./") || Startswith(*I, "/")) && + DirectoryExists(*I)) + { + ioprintf(c1out, _("Note, using directory '%s' to get the build dependencies\n"), *I); + // FIXME: how can we make this more elegant? + std::string TypeName = "Debian control file"; + pkgIndexFile::Type *Type = pkgIndexFile::Type::GetType(TypeName.c_str()); + if(Type != NULL) + LastOwner = Last = Type->CreateSrcPkgParser(*I); + } + // if its a local file (e.g. .dsc) use this + else if (FileExists(*I)) + { + ioprintf(c1out, _("Note, using file '%s' to get the build dependencies\n"), *I); + + // see if we can get a parser for this pkgIndexFile type + string TypeName = "Debian " + flExtension(*I) + " file"; + pkgIndexFile::Type *Type = pkgIndexFile::Type::GetType(TypeName.c_str()); + if(Type != NULL) + LastOwner = Last = Type->CreateSrcPkgParser(*I); + } else { + // normal case, search the cache for the source file +#if APT_PKG_ABI >= 413 + Last = FindSrc(*I,SrcRecs,Src,Cache); +#else + Last = FindSrc(*I,Recs,SrcRecs,Src,Cache); +#endif + } + if (Last == 0) return _error->Error(_("Unable to find a source package for %s"),Src.c_str()); @@ -983,7 +1086,7 @@ bool DoBuildDep(CommandLine &CmdL) } else if (Last->BuildDepends(BuildDeps, _config->FindB("APT::Get::Arch-Only", false), StripMultiArch) == false) return _error->Error(_("Unable to get build-dependency information for %s"),Src.c_str()); - + // Also ensure that build-essential packages are present Configuration::Item const *Opts = _config->Tree("APT::Build-Essential"); if (Opts) @@ -1305,197 +1408,189 @@ bool DoBuildDep(CommandLine &CmdL) return true; } /*}}}*/ -// GetChangelogPath - return a path pointing to a changelog file or dir /*{{{*/ -// --------------------------------------------------------------------- -/* This returns a "path" string for the changelog url construction. - * Please note that its not complete, it either needs a "/changelog" - * appended (for the packages.debian.org/changelogs site) or a - * ".changelog" (for third party sites that store the changelog in the - * pool/ next to the deb itself) - * Example return: "pool/main/a/apt/apt_0.8.8ubuntu3" - */ -string GetChangelogPath(CacheFile &Cache, - pkgCache::PkgIterator Pkg, - pkgCache::VerIterator Ver) -{ - string path; - - pkgRecords Recs(Cache); - pkgRecords::Parser &rec=Recs.Lookup(Ver.FileList()); - string srcpkg = rec.SourcePkg().empty() ? Pkg.Name() : rec.SourcePkg(); - string ver = Ver.VerStr(); - // if there is a source version it always wins - if (rec.SourceVer() != "") - ver = rec.SourceVer(); - path = flNotFile(rec.FileName()); - path += srcpkg + "_" + StripEpoch(ver); - return path; -} - /*}}}*/ -// GuessThirdPartyChangelogUri - return url /*{{{*/ -// --------------------------------------------------------------------- -/* Contruct a changelog file path for third party sites that do not use - * packages.debian.org/changelogs - * This simply uses the ArchiveURI() of the source pkg and looks for - * a .changelog file there, Example for "mediabuntu": - * apt-get changelog mplayer-doc: - * http://packages.medibuntu.org/pool/non-free/m/mplayer/mplayer_1.0~rc4~try1.dsfg1-1ubuntu1+medibuntu1.changelog - */ -bool GuessThirdPartyChangelogUri(CacheFile &Cache, - pkgCache::PkgIterator Pkg, - pkgCache::VerIterator Ver, - string &out_uri) +// DoChangelog - Get changelog from the command line /*{{{*/ +static bool DoChangelog(CommandLine &CmdL) { - // get the binary deb server path - pkgCache::VerFileIterator Vf = Ver.FileList(); - if (Vf.end() == true) + CacheFile Cache; + if (Cache.ReadOnlyOpen() == false) return false; - pkgCache::PkgFileIterator F = Vf.File(); - pkgIndexFile *index; - pkgSourceList *SrcList = Cache.GetSourceList(); - if(SrcList->FindIndex(F, index) == false) + + APT::CacheSetHelper helper; + APT::VersionList verset = APT::VersionList::FromCommandLine(Cache, + CmdL.FileList + 1, APT::CacheSetHelper::CANDIDATE, helper); + if (verset.empty() == true) return false; + pkgAcquire Fetcher; + AcqTextStatus Stat(std::cout, ScreenWidth,_config->FindI("quiet",0)); + Fetcher.SetLog(&Stat); - // get archive uri for the binary deb - string path_without_dot_changelog = GetChangelogPath(Cache, Pkg, Ver); - out_uri = index->ArchiveURI(path_without_dot_changelog + ".changelog"); + bool const downOnly = _config->FindB("APT::Get::Download-Only", false); + bool const printOnly = _config->FindB("APT::Get::Print-URIs", false); - // now strip away the filename and add srcpkg_srcver.changelog - return true; -} - /*}}}*/ -// DownloadChangelog - Download the changelog /*{{{*/ -// --------------------------------------------------------------------- -bool DownloadChangelog(CacheFile &CacheFile, pkgAcquire &Fetcher, - pkgCache::VerIterator Ver, string targetfile) -/* Download a changelog file for the given package version to - * targetfile. This will first try the server from Apt::Changelogs::Server - * (http://packages.debian.org/changelogs by default) and if that gives - * a 404 tries to get it from the archive directly (see - * GuessThirdPartyChangelogUri for details how) - */ -{ - string path; - string descr; - string server; - string changelog_uri; - - // data structures we need - pkgCache::PkgIterator Pkg = Ver.ParentPkg(); - - // make the server root configurable - server = _config->Find("Apt::Changelogs::Server", - "http://packages.debian.org/changelogs"); - path = GetChangelogPath(CacheFile, Pkg, Ver); - strprintf(changelog_uri, "%s/%s/changelog", server.c_str(), path.c_str()); - if (_config->FindB("APT::Get::Print-URIs", false) == true) + for (APT::VersionList::const_iterator Ver = verset.begin(); + Ver != verset.end(); + ++Ver) { - std::cout << '\'' << changelog_uri << '\'' << std::endl; - return true; + if (printOnly) + new pkgAcqChangelog(&Fetcher, Ver, "/dev/null"); + else if (downOnly) + new pkgAcqChangelog(&Fetcher, Ver, "."); + else + new pkgAcqChangelog(&Fetcher, Ver); } - strprintf(descr, _("Changelog for %s (%s)"), Pkg.Name(), changelog_uri.c_str()); - // queue it - new pkgAcqFile(&Fetcher, changelog_uri, "", 0, descr, Pkg.Name(), "ignored", targetfile); + if (printOnly == false) + { + // Disable drop-privs if "_apt" can not write to the target dir + CheckDropPrivsMustBeDisabled(Fetcher); + if (_error->PendingError() == true) + return false; - // try downloading it, if that fails, try third-party-changelogs location - // FIXME: Fetcher.Run() is "Continue" even if I get a 404?!? - Fetcher.Run(); - if (!FileExists(targetfile)) + bool Failed = false; + if (AcquireRun(Fetcher, 0, &Failed, NULL) == false || Failed == true) + return false; + } + + if (downOnly == false || printOnly == true) { - string third_party_uri; - if (GuessThirdPartyChangelogUri(CacheFile, Pkg, Ver, third_party_uri)) + bool Failed = false; + for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); ++I) { - strprintf(descr, _("Changelog for %s (%s)"), Pkg.Name(), third_party_uri.c_str()); - new pkgAcqFile(&Fetcher, third_party_uri, "", 0, descr, Pkg.Name(), "ignored", targetfile); - Fetcher.Run(); + if (printOnly) + { + if ((*I)->ErrorText.empty() == false) + { + Failed = true; + _error->Error("%s", (*I)->ErrorText.c_str()); + } + else + cout << '\'' << (*I)->DescURI() << "' " << flNotDir((*I)->DestFile) << std::endl; + } + else + DisplayFileInPager((*I)->DestFile); } + return Failed == false; } - if (FileExists(targetfile)) - return true; - - // error - return _error->Error("changelog download failed"); + return true; } /*}}}*/ -// DoChangelog - Get changelog from the command line /*{{{*/ -// --------------------------------------------------------------------- -bool DoChangelog(CommandLine &CmdL) +// DoFiles - Lists all IndexTargets /*{{{*/ +static std::string format_key(std::string key) { - CacheFile Cache; - if (Cache.ReadOnlyOpen() == false) - return false; - - APT::CacheSetHelper helper(c0out); - APT::VersionList verset = APT::VersionList::FromCommandLine(Cache, - CmdL.FileList + 1, APT::VersionList::CANDIDATE, helper); - if (verset.empty() == true) - return false; - pkgAcquire Fetcher; - - if (_config->FindB("APT::Get::Print-URIs", false) == true) + // deb822 is case-insensitive, but the human eye prefers candy + std::transform(key.begin(), key.end(), key.begin(), ::tolower); + key[0] = ::toupper(key[0]); + size_t found = key.find("_uri"); + if (found != std::string::npos) + key.replace(found, 4, "-URI"); + while ((found = key.find('_')) != std::string::npos) { - bool Success = true; - for (APT::VersionList::const_iterator Ver = verset.begin(); - Ver != verset.end(); ++Ver) - Success &= DownloadChangelog(Cache, Fetcher, Ver, ""); - return Success; + key[found] = '-'; + key[found + 1] = ::toupper(key[found + 1]); } + return key; +} +static bool DoFiles(CommandLine &CmdL) +{ + pkgCacheFile CacheFile; + pkgSourceList *SrcList = CacheFile.GetSourceList(); - AcqTextStatus Stat(ScreenWidth, _config->FindI("quiet",0)); - Fetcher.Setup(&Stat); - - bool const downOnly = _config->FindB("APT::Get::Download-Only", false); + if (SrcList == NULL) + return false; - char tmpname[100]; - char* tmpdir = NULL; - if (downOnly == false) + std::string const Format = _config->Find("APT::Get::Files::Format"); + bool const ReleaseInfo = _config->FindB("APT::Get::Files::ReleaseInfo", true); + bool Filtered = CmdL.FileSize() > 1; + for (pkgSourceList::const_iterator S = SrcList->begin(); S != SrcList->end(); ++S) { - const char* const tmpDir = getenv("TMPDIR"); - if (tmpDir != NULL && *tmpDir != '\0') - snprintf(tmpname, sizeof(tmpname), "%s/apt-changelog-XXXXXX", tmpDir); - else - strncpy(tmpname, "/tmp/apt-changelog-XXXXXX", sizeof(tmpname)); - tmpdir = mkdtemp(tmpname); - if (tmpdir == NULL) - return _error->Errno("mkdtemp", "mkdtemp failed"); - } + std::vector const targets = (*S)->GetIndexTargets(); + std::map AddOptions; + if (ReleaseInfo) + { + AddOptions.insert(std::make_pair("TRUSTED", ((*S)->IsTrusted() ? "yes" : "no"))); + pkgCache &Cache = *CacheFile.GetPkgCache(); + pkgCache::RlsFileIterator const RlsFile = (*S)->FindInCache(Cache, false); + if (RlsFile.end()) + continue; +#define APT_RELEASE(X,Y) if (RlsFile.Y() != NULL) AddOptions.insert(std::make_pair(X, RlsFile.Y())) + APT_RELEASE("CODENAME", Codename); + APT_RELEASE("SUITE", Archive); + APT_RELEASE("VERSION", Version); + APT_RELEASE("ORIGIN", Origin); + APT_RELEASE("LABEL", Label); +#undef APT_RELEASE + } - for (APT::VersionList::const_iterator Ver = verset.begin(); - Ver != verset.end(); - ++Ver) - { - string changelogfile; - if (downOnly == false) - changelogfile.append(tmpname).append("changelog"); - else - changelogfile.append(Ver.ParentPkg().Name()).append(".changelog"); - if (DownloadChangelog(Cache, Fetcher, Ver, changelogfile) && downOnly == false) + for (std::vector::const_iterator T = targets.begin(); T != targets.end(); ++T) { - DisplayFileInPager(changelogfile); - // cleanup temp file - unlink(changelogfile.c_str()); + std::string filename = T->Option(ReleaseInfo ? IndexTarget::EXISTING_FILENAME : IndexTarget::FILENAME); + if (filename.empty()) + continue; + + std::ostringstream stanza; + if (Filtered || Format.empty()) + { + stanza << "MetaKey: " << T->MetaKey << "\n" + << "ShortDesc: " << T->ShortDesc << "\n" + << "Description: " << T->Description << "\n" + << "URI: " << T->URI << "\n" + << "Filename: " << filename << "\n" + << "Optional: " << (T->IsOptional ? "yes" : "no") << "\n"; + for (std::map::const_iterator O = AddOptions.begin(); O != AddOptions.end(); ++O) + stanza << format_key(O->first) << ": " << O->second << "\n"; + for (std::map::const_iterator O = T->Options.begin(); O != T->Options.end(); ++O) + stanza << format_key(O->first) << ": " << O->second << "\n"; + stanza << "\n"; + + if (Filtered) + { + // that is a bit crude, but good enough for now + bool found = true; + std::string haystack = std::string("\n") + stanza.str() + "\n"; + std::transform(haystack.begin(), haystack.end(), haystack.begin(), ::tolower); + size_t const filesize = CmdL.FileSize() - 1; + for (size_t i = 0; i != filesize; ++i) + { + std::string needle = std::string("\n") + CmdL.FileList[i + 1] + "\n"; + std::transform(needle.begin(), needle.end(), needle.begin(), ::tolower); + if (haystack.find(needle) != std::string::npos) + continue; + found = false; + break; + } + if (found == false) + continue; + } + } + + if (Format.empty()) + cout << stanza.str(); + else + { + std::string out = SubstVar(Format, "$(FILENAME)", filename); + out = T->Format(out); + for (std::map::const_iterator O = AddOptions.begin(); O != AddOptions.end(); ++O) + out = SubstVar(out, std::string("$(") + O->first + ")", O->second); + cout << out << std::endl; + } } } - // clenaup tmp dir - if (tmpdir != NULL) - rmdir(tmpdir); + return true; } /*}}}*/ // ShowHelp - Show a help screen /*{{{*/ // --------------------------------------------------------------------- /* */ -bool ShowHelp(CommandLine &CmdL) +static bool ShowHelp(CommandLine &) { - ioprintf(cout,_("%s %s for %s compiled on %s %s\n"),PACKAGE,PACKAGE_VERSION, - COMMON_ARCH,__DATE__,__TIME__); - + ioprintf(cout, "%s %s (%s)\n", PACKAGE, PACKAGE_VERSION, COMMON_ARCH); + if (_config->FindB("version") == true) { cout << _("Supported modules:") << endl; - + for (unsigned I = 0; I != pkgVersioningSystem::GlobalListLen; I++) { pkgVersioningSystem *VS = pkgVersioningSystem::GlobalList[I]; @@ -1504,7 +1599,7 @@ bool ShowHelp(CommandLine &CmdL) else cout << ' '; cout << "Ver: " << VS->Label << endl; - + /* Print out all the packaging systems that will work with this VS */ for (unsigned J = 0; J != pkgSystem::GlobalListLen; J++) @@ -1580,28 +1675,6 @@ bool ShowHelp(CommandLine &CmdL) return true; } /*}}}*/ -// SigWinch - Window size change signal handler /*{{{*/ -// --------------------------------------------------------------------- -/* */ -void SigWinch(int) -{ - // Riped from GNU ls -#ifdef TIOCGWINSZ - struct winsize ws; - - if (ioctl(1, TIOCGWINSZ, &ws) != -1 && ws.ws_col >= 5) - ScreenWidth = ws.ws_col - 1; -#endif -} - /*}}}*/ -bool DoUpgrade(CommandLine &CmdL) /*{{{*/ -{ - if (_config->FindB("APT::Get::Upgrade-Allow-New", false) == true) - return DoUpgradeWithAllowNewPackages(CmdL); - else - return DoUpgradeNoNewPackages(CmdL); -} - /*}}}*/ int main(int argc,const char *argv[]) /*{{{*/ { CommandLine::Dispatch Cmds[] = {{"update",&DoUpdate}, @@ -1621,6 +1694,7 @@ int main(int argc,const char *argv[]) /*{{{*/ {"source",&DoSource}, {"download",&DoDownload}, {"changelog",&DoChangelog}, + {"files",&DoFiles}, {"moo",&DoMoo}, {"help",&ShowHelp}, {0,0}}; @@ -1632,42 +1706,18 @@ int main(int argc,const char *argv[]) /*{{{*/ textdomain(PACKAGE); // Parse the command line and initialize the package library - CommandLine CmdL(Args.data(),_config); - if (pkgInitConfig(*_config) == false || - CmdL.Parse(argc,argv) == false || - pkgInitSystem(*_config,_system) == false) - { - if (_config->FindB("version") == true) - ShowHelp(CmdL); - - _error->DumpErrors(); - return 100; - } - - // See if the help should be shown - if (_config->FindB("help") == true || - _config->FindB("version") == true || - CmdL.FileSize() == 0) - { - ShowHelp(CmdL); - return 0; - } + CommandLine CmdL; + ParseCommandLine(CmdL, Cmds, Args.data(), &_config, &_system, argc, argv, ShowHelp); // see if we are in simulate mode CheckSimulateMode(CmdL); - // Deal with stdout not being a tty - if (!isatty(STDOUT_FILENO) && _config->FindI("quiet", -1) == -1) - _config->Set("quiet","1"); + // Init the signals + InitSignals(); // Setup the output streams InitOutput(); - // Setup the signals - signal(SIGPIPE,SIG_IGN); - signal(SIGWINCH,SigWinch); - SigWinch(0); - // Match the operation CmdL.DispatchArg(Cmds);