X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/ce7f128c020e1347f91c6074238fc5da58c5df71..463c8d801595ce5ac94d7c032264820be7434232:/cmdline/apt-get.cc diff --git a/cmdline/apt-get.cc b/cmdline/apt-get.cc index f8de80a91..500a0a3c5 100644 --- a/cmdline/apt-get.cc +++ b/cmdline/apt-get.cc @@ -27,66 +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 #include /*}}}*/ @@ -97,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) { @@ -134,32 +137,10 @@ bool TryToInstallBuildDep(pkgCache::PkgIterator Pkg,pkgCacheFile &Cache, return true; } /*}}}*/ - - -// helper that can go wit hthe next ABI break -#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR < 13) -std::string MetaIndexFileNameOnDisk(metaIndex *metaindex) -{ - // FIXME: this cast is the horror, the horror - debReleaseIndex *r = (debReleaseIndex*)metaindex; - - // see if we have a InRelease file - std::string PathInRelease = r->MetaIndexFile("InRelease"); - if (FileExists(PathInRelease)) - return PathInRelease; - - // and if not return the normal one - if (FileExists(PathInRelease)) - return r->MetaIndexFile("Release"); - - return ""; -} -#endif - // GetReleaseForSourceRecord - Return Suite for the given srcrecord /*{{{*/ // --------------------------------------------------------------------- /* */ -std::string GetReleaseForSourceRecord(pkgSourceList *SrcList, +static std::string GetReleaseForSourceRecord(pkgSourceList *SrcList, pkgSrcRecords::Parser *Parse) { // try to find release @@ -174,12 +155,8 @@ std::string GetReleaseForSourceRecord(pkgSourceList *SrcList, { if (&CurrentIndexFile == (*IF)) { -#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR < 13) - std::string path = MetaIndexFileNameOnDisk(*S); -#else - std::string path = (*S)->LocalFileName(); -#endif - if (path != "") + std::string const path = (*S)->LocalFileName(); + if (path != "") { indexRecords records; records.Load(path); @@ -194,7 +171,11 @@ std::string GetReleaseForSourceRecord(pkgSourceList *SrcList, // 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) { @@ -302,16 +283,21 @@ pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs, (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; } } @@ -342,10 +328,17 @@ pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs, 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 } } } @@ -430,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; @@ -475,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) @@ -539,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")); @@ -551,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; @@ -599,7 +588,7 @@ class LogCleaner : public pkgArchiveCleaner }; }; -bool DoAutoClean(CommandLine &CmdL) +static bool DoAutoClean(CommandLine &) { // Lock the archive directory FileFd Lock; @@ -623,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::CacheSetHelper helper; APT::VersionSet verset = APT::VersionSet::FromCommandLine(Cache, - CmdL.FileList + 1, APT::VersionSet::CANDIDATE, helper); + 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(); @@ -654,6 +641,8 @@ bool DoDownload(CommandLine &CmdL) 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); @@ -664,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; @@ -696,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(); @@ -715,7 +707,7 @@ struct DscFile string Dsc; }; -bool DoSource(CommandLine &CmdL) +static bool DoSource(CommandLine &CmdL) { CacheFile Cache; if (Cache.Open(false) == false) @@ -730,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 @@ -755,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-"); @@ -793,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. @@ -829,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 @@ -895,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) { @@ -906,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; } @@ -952,18 +933,19 @@ 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) { @@ -979,23 +961,22 @@ bool DoSource(CommandLine &CmdL) 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; @@ -1016,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; @@ -1034,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) @@ -1061,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()); @@ -1079,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) @@ -1401,195 +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; + + bool Failed = false; + if (AcquireRun(Fetcher, 0, &Failed, NULL) == false || Failed == 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)) + 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]; - const 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) { - std::string systemTemp = GetTempDir(); - snprintf(tmpname, sizeof(tmpname), "%s/apt-changelog-XXXXXX", - systemTemp.c_str()); - 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]; @@ -1598,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++) @@ -1672,20 +1673,6 @@ bool ShowHelp(CommandLine &CmdL) "pages for more information and options.\n" " This APT has Super Cow Powers.\n"); 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 } /*}}}*/ int main(int argc,const char *argv[]) /*{{{*/ @@ -1707,6 +1694,7 @@ int main(int argc,const char *argv[]) /*{{{*/ {"source",&DoSource}, {"download",&DoDownload}, {"changelog",&DoChangelog}, + {"files",&DoFiles}, {"moo",&DoMoo}, {"help",&ShowHelp}, {0,0}}; @@ -1718,38 +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); + // 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);