From a4c404301df135bea81f23b944dc6e1967f9ca85 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Mon, 15 Nov 2010 12:12:56 +0100 Subject: initial apt-get changelog implementation, not quite ready yet (need to get rid of tmpnam --- cmdline/apt-get.cc | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) (limited to 'cmdline') diff --git a/cmdline/apt-get.cc b/cmdline/apt-get.cc index 8efcd0e2e..72c1ef0b0 100644 --- a/cmdline/apt-get.cc +++ b/cmdline/apt-get.cc @@ -2733,6 +2733,104 @@ bool DoBuildDep(CommandLine &CmdL) return true; } /*}}}*/ +// DownloadChangelog - Download the changelog /*{{{*/ +// --------------------------------------------------------------------- +string DownloadChangelog(CacheFile &CacheFile, pkgAcquire &Fetcher, pkgCache::VerIterator V) +{ + string uri; + string srcpkg; + string prefix; + string descr; + string src_section; + string verstr; + + // data structures we need + pkgRecords Recs(CacheFile); + pkgCache::PkgIterator Pkg = V.ParentPkg(); + pkgRecords::Parser &rec=Recs.Lookup(V.FileList()); + + // build uri + srcpkg = rec.SourcePkg().empty() ? Pkg.Name() : rec.SourcePkg(); + strprintf(descr, _("Changelog for %s"), srcpkg.c_str()); + // FIXME: we actually need the source section here + src_section= Pkg.Section(); + if(src_section.find('/')!=src_section.npos) + src_section=string(src_section, 0, src_section.find('/')); + else + src_section="main"; + + prefix+=srcpkg[0]; + if(srcpkg.size()>3 && srcpkg[0]=='l' && srcpkg[1]=='i' && srcpkg[2]=='b') + prefix=std::string("lib")+srcpkg[3]; + + verstr = V.VerStr(); + if(verstr.find(':')!=verstr.npos) + verstr=string(verstr, verstr.find(':')+1); + + strprintf(uri, "http://packages.debian.org/changelogs/pool/%s/%s/%s/%s_%s/changelog", src_section.c_str(), prefix.c_str(), srcpkg.c_str(), srcpkg.c_str(), verstr.c_str()); + + AcqTextStatus Stat(ScreenWidth, _config->FindI("quiet",0)); + Fetcher.Setup(&Stat); + + // temp file + string targetfile = tmpnam(strdup("apt-changelog-XXXXXX")); + new pkgAcqFile(&Fetcher, uri, "", 0, descr, srcpkg, "ignore", targetfile); + + // get it + int res = Fetcher.Run(); + if (FileExists(targetfile)) + return targetfile; + + // error + return ""; +} + /*}}}*/ +// DisplayFileInPager - Display File with pager /*{{{*/ +void DisplayFileInPager(string filename) +{ + pid_t Process = ExecFork(); + if (Process == 0) + { + const char *Args[3]; + Args[0] = "/usr/bin/sensible-pager"; + Args[1] = filename.c_str(); + Args[2] = 0; + execvp(Args[0],(char **)Args); + exit(100); + } + + // Wait for the subprocess + ExecWait(Process, "sensible-pager", false); +} + /*}}}*/ +// DoChangelog - Get changelog from the command line /*{{{*/ +// --------------------------------------------------------------------- +bool DoChangelog(CommandLine &CmdL) +{ + CacheFile Cache; + if (Cache.ReadOnlyOpen() == false) + return false; + + APT::CacheSetHelper helper(c0out); + APT::VersionSet verset = APT::VersionSet::FromCommandLine(Cache, + CmdL.FileList + 1, APT::VersionSet::CANDIDATE, helper); + pkgAcquire Fetcher; + + if (verset.empty() == true) + return false; + for (APT::VersionSet::const_iterator Ver = verset.begin(); + Ver != verset.end(); + ++Ver) + { + string changelogfile = DownloadChangelog(Cache, Fetcher, Ver); + if (changelogfile.size() > 0) + { + DisplayFileInPager(changelogfile); + unlink(changelogfile.c_str()); + } + } +} + /*}}}*/ // DoMoo - Never Ask, Never Tell /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -2923,6 +3021,7 @@ int main(int argc,const char *argv[]) /*{{{*/ {"autoclean",&DoAutoClean}, {"check",&DoCheck}, {"source",&DoSource}, + {"changelog",&DoChangelog}, {"moo",&DoMoo}, {"help",&ShowHelp}, {0,0}}; -- cgit v1.2.3 From 4a6fe09cf2a7f18de2f80a1b79ea43e211302dbc Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Mon, 15 Nov 2010 12:26:39 +0100 Subject: use mkdtemp() instead of tempnam, free mkdtemp() data afterwards, return true in DoChangelog handler --- cmdline/apt-get.cc | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'cmdline') diff --git a/cmdline/apt-get.cc b/cmdline/apt-get.cc index 72c1ef0b0..0d67585a7 100644 --- a/cmdline/apt-get.cc +++ b/cmdline/apt-get.cc @@ -2773,11 +2773,18 @@ string DownloadChangelog(CacheFile &CacheFile, pkgAcquire &Fetcher, pkgCache::Ve Fetcher.Setup(&Stat); // temp file - string targetfile = tmpnam(strdup("apt-changelog-XXXXXX")); - new pkgAcqFile(&Fetcher, uri, "", 0, descr, srcpkg, "ignore", targetfile); + char *tmpdir = mkdtemp(strdup("apt-changelog-XXXXXX")); + if (tmpdir == NULL) { + _error->Errno("mkdtemp", "mkdtemp failed"); + return ""; + } + string targetfile = string(tmpdir) + "changelog"; // get it + new pkgAcqFile(&Fetcher, uri, "", 0, descr, srcpkg, tmpdir); int res = Fetcher.Run(); + free(tmpdir); + if (FileExists(targetfile)) return targetfile; @@ -2826,9 +2833,12 @@ bool DoChangelog(CommandLine &CmdL) if (changelogfile.size() > 0) { DisplayFileInPager(changelogfile); + // cleanup unlink(changelogfile.c_str()); + rmdir(flNotFile(changelogfile).c_str()); } } + return true; } /*}}}*/ // DoMoo - Never Ask, Never Tell /*{{{*/ -- cgit v1.2.3 From 18ae8b296bf08b853c44fdd5c20689e45ae71bfc Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Mon, 15 Nov 2010 12:53:52 +0100 Subject: support Apt::Changelog::Server, code cleanup --- cmdline/apt-get.cc | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) (limited to 'cmdline') diff --git a/cmdline/apt-get.cc b/cmdline/apt-get.cc index 0d67585a7..a61bcc62b 100644 --- a/cmdline/apt-get.cc +++ b/cmdline/apt-get.cc @@ -2735,7 +2735,7 @@ bool DoBuildDep(CommandLine &CmdL) /*}}}*/ // DownloadChangelog - Download the changelog /*{{{*/ // --------------------------------------------------------------------- -string DownloadChangelog(CacheFile &CacheFile, pkgAcquire &Fetcher, pkgCache::VerIterator V) +bool DownloadChangelog(CacheFile &CacheFile, pkgAcquire &Fetcher, pkgCache::VerIterator V, string targetfile) { string uri; string srcpkg; @@ -2767,29 +2767,22 @@ string DownloadChangelog(CacheFile &CacheFile, pkgAcquire &Fetcher, pkgCache::Ve if(verstr.find(':')!=verstr.npos) verstr=string(verstr, verstr.find(':')+1); - strprintf(uri, "http://packages.debian.org/changelogs/pool/%s/%s/%s/%s_%s/changelog", src_section.c_str(), prefix.c_str(), srcpkg.c_str(), srcpkg.c_str(), verstr.c_str()); + string fmt = _config->Find("Apt::Changelogs::Server", + "http://packages.debian.org/changelogs/pool/%s/%s/%s/%s_%s/changelog"); + strprintf(uri, fmt.c_str(), src_section.c_str(), prefix.c_str(), srcpkg.c_str(), srcpkg.c_str(), verstr.c_str()); AcqTextStatus Stat(ScreenWidth, _config->FindI("quiet",0)); Fetcher.Setup(&Stat); - // temp file - char *tmpdir = mkdtemp(strdup("apt-changelog-XXXXXX")); - if (tmpdir == NULL) { - _error->Errno("mkdtemp", "mkdtemp failed"); - return ""; - } - string targetfile = string(tmpdir) + "changelog"; - // get it - new pkgAcqFile(&Fetcher, uri, "", 0, descr, srcpkg, tmpdir); + new pkgAcqFile(&Fetcher, uri, "", 0, descr, srcpkg, "ignored", targetfile); int res = Fetcher.Run(); - free(tmpdir); if (FileExists(targetfile)) - return targetfile; + return true; // error - return ""; + return _error->Error("changelog download failed"); } /*}}}*/ // DisplayFileInPager - Display File with pager /*{{{*/ @@ -2825,19 +2818,24 @@ bool DoChangelog(CommandLine &CmdL) if (verset.empty() == true) return false; + char *tmpdir = mkdtemp(strdup("apt-changelog-XXXXXX")); + if (tmpdir == NULL) { + return _error->Errno("mkdtemp", "mkdtemp failed"); + } + for (APT::VersionSet::const_iterator Ver = verset.begin(); Ver != verset.end(); ++Ver) { - string changelogfile = DownloadChangelog(Cache, Fetcher, Ver); - if (changelogfile.size() > 0) - { + string changelogfile = string(tmpdir) + "changelog"; + if (DownloadChangelog(Cache, Fetcher, Ver, changelogfile)) DisplayFileInPager(changelogfile); - // cleanup - unlink(changelogfile.c_str()); - rmdir(flNotFile(changelogfile).c_str()); - } + // cleanup temp file + unlink(changelogfile.c_str()); } + // clenaup tmp dir + rmdir(tmpdir); + free(tmpdir); return true; } /*}}}*/ -- cgit v1.2.3 From c2991635eb1d2a6bc8a0910b4f84748415a3ac14 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Mon, 15 Nov 2010 13:28:22 +0100 Subject: cmdline/apt-get.cc make only the server configurable, but not the format string (attack vector?) --- cmdline/apt-get.cc | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'cmdline') diff --git a/cmdline/apt-get.cc b/cmdline/apt-get.cc index a61bcc62b..a5e3ad454 100644 --- a/cmdline/apt-get.cc +++ b/cmdline/apt-get.cc @@ -2737,12 +2737,13 @@ bool DoBuildDep(CommandLine &CmdL) // --------------------------------------------------------------------- bool DownloadChangelog(CacheFile &CacheFile, pkgAcquire &Fetcher, pkgCache::VerIterator V, string targetfile) { - string uri; string srcpkg; string prefix; string descr; string src_section; string verstr; + string server; + string path; // data structures we need pkgRecords Recs(CacheFile); @@ -2767,15 +2768,16 @@ bool DownloadChangelog(CacheFile &CacheFile, pkgAcquire &Fetcher, pkgCache::VerI if(verstr.find(':')!=verstr.npos) verstr=string(verstr, verstr.find(':')+1); - string fmt = _config->Find("Apt::Changelogs::Server", - "http://packages.debian.org/changelogs/pool/%s/%s/%s/%s_%s/changelog"); - strprintf(uri, fmt.c_str(), src_section.c_str(), prefix.c_str(), srcpkg.c_str(), srcpkg.c_str(), verstr.c_str()); - + // make the server configurable + server = _config->Find("Apt::Changelogs::Server", + "http://packages.debian.org/"); + // ... but not the format string to avoid all possible attacks + strprintf(path, "/changelogs/pool/%s/%s/%s/%s_%s/changelog", src_section.c_str(), prefix.c_str(), srcpkg.c_str(), srcpkg.c_str(), verstr.c_str()); AcqTextStatus Stat(ScreenWidth, _config->FindI("quiet",0)); Fetcher.Setup(&Stat); // get it - new pkgAcqFile(&Fetcher, uri, "", 0, descr, srcpkg, "ignored", targetfile); + new pkgAcqFile(&Fetcher, server+path, "", 0, descr, srcpkg, "ignored", targetfile); int res = Fetcher.Run(); if (FileExists(targetfile)) -- cgit v1.2.3 From 8cc74fb1f791935bea9afd767fddf78ecebd4740 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Mon, 15 Nov 2010 13:34:36 +0100 Subject: cmdline/apt-get.cc: move Setup a level higher --- cmdline/apt-get.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'cmdline') diff --git a/cmdline/apt-get.cc b/cmdline/apt-get.cc index a5e3ad454..cf4f1ab36 100644 --- a/cmdline/apt-get.cc +++ b/cmdline/apt-get.cc @@ -2773,9 +2773,6 @@ bool DownloadChangelog(CacheFile &CacheFile, pkgAcquire &Fetcher, pkgCache::VerI "http://packages.debian.org/"); // ... but not the format string to avoid all possible attacks strprintf(path, "/changelogs/pool/%s/%s/%s/%s_%s/changelog", src_section.c_str(), prefix.c_str(), srcpkg.c_str(), srcpkg.c_str(), verstr.c_str()); - AcqTextStatus Stat(ScreenWidth, _config->FindI("quiet",0)); - Fetcher.Setup(&Stat); - // get it new pkgAcqFile(&Fetcher, server+path, "", 0, descr, srcpkg, "ignored", targetfile); int res = Fetcher.Run(); @@ -2817,6 +2814,8 @@ bool DoChangelog(CommandLine &CmdL) APT::VersionSet verset = APT::VersionSet::FromCommandLine(Cache, CmdL.FileList + 1, APT::VersionSet::CANDIDATE, helper); pkgAcquire Fetcher; + AcqTextStatus Stat(ScreenWidth, _config->FindI("quiet",0)); + Fetcher.Setup(&Stat); if (verset.empty() == true) return false; -- cgit v1.2.3 From 64b4c03ee79d5df053df7dabd33e88e0ebef1f20 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Mon, 15 Nov 2010 13:54:47 +0100 Subject: cmdline/apt-get.cc: create the mkdtemp dir in /tmp --- cmdline/apt-get.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'cmdline') diff --git a/cmdline/apt-get.cc b/cmdline/apt-get.cc index cf4f1ab36..53def383d 100644 --- a/cmdline/apt-get.cc +++ b/cmdline/apt-get.cc @@ -2819,7 +2819,7 @@ bool DoChangelog(CommandLine &CmdL) if (verset.empty() == true) return false; - char *tmpdir = mkdtemp(strdup("apt-changelog-XXXXXX")); + char *tmpdir = mkdtemp(strdup("/tmp/apt-changelog-XXXXXX")); if (tmpdir == NULL) { return _error->Errno("mkdtemp", "mkdtemp failed"); } -- cgit v1.2.3 From cdb9307c701fd016325c83dc879351912fb35c9d Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Tue, 16 Nov 2010 10:35:10 +0100 Subject: add support for third party changelogs --- apt-pkg/contrib/strutl.cc | 9 +++++++++ apt-pkg/contrib/strutl.h | 1 + cmdline/apt-get.cc | 42 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+) (limited to 'cmdline') diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc index 987f4c3a4..c2b335ed7 100644 --- a/apt-pkg/contrib/strutl.cc +++ b/apt-pkg/contrib/strutl.cc @@ -1174,6 +1174,15 @@ char *safe_snprintf(char *Buffer,char *End,const char *Format,...) return Buffer + Did; } /*}}}*/ +// StripEpoch - Remove the version "epoch" from a version string /*{{{*/ +// --------------------------------------------------------------------- +string StripEpoch(const string &VerStr) +{ + size_t i = VerStr.find(":"); + if (i == string::npos) + return VerStr; + return VerStr.substr(i+1); +} // tolower_ascii - tolower() function that ignores the locale /*{{{*/ // --------------------------------------------------------------------- diff --git a/apt-pkg/contrib/strutl.h b/apt-pkg/contrib/strutl.h index a457ff047..14cf5c943 100644 --- a/apt-pkg/contrib/strutl.h +++ b/apt-pkg/contrib/strutl.h @@ -61,6 +61,7 @@ void strprintf(string &out,const char *format,...) __like_printf(2); char *safe_snprintf(char *Buffer,char *End,const char *Format,...) __like_printf(3); bool CheckDomainList(const string &Host, const string &List); int tolower_ascii(int const c) __attrib_const __hot; +string StripEpoch(const string &VerStr); #define APT_MKSTRCMP(name,func) \ inline int name(const char *A,const char *B) {return func(A,A+strlen(A),B,B+strlen(B));}; \ diff --git a/cmdline/apt-get.cc b/cmdline/apt-get.cc index 53def383d..35f37cc49 100644 --- a/cmdline/apt-get.cc +++ b/cmdline/apt-get.cc @@ -2733,6 +2733,37 @@ bool DoBuildDep(CommandLine &CmdL) return true; } /*}}}*/ +// GuessThirdPartyChangelogUri - return url /*{{{*/ +// --------------------------------------------------------------------- +bool GuessThirdPartyChangelogUri(CacheFile &Cache, + pkgCache::PkgIterator Pkg, + pkgCache::VerIterator Ver, + string &out_uri) +{ + pkgRecords Recs(Cache); + pkgSourceList *SrcList = Cache.GetSourceList(); + + // get the binary deb server path + pkgRecords::Parser &rec=Recs.Lookup(Ver.FileList()); + string srcpkg = rec.SourcePkg().empty() ? Pkg.Name() : rec.SourcePkg(); + // FIXME: deal with cases like gcc-defaults (srcver != binver) + string srcver = StripEpoch(Ver.VerStr()); + + pkgCache::VerFileIterator Vf = Ver.FileList(); + if (Vf.end() == true) + return false; + pkgCache::PkgFileIterator F = Vf.File(); + pkgIndexFile *index; + if(SrcList->FindIndex(F, index) == false) + return false; + // get archive uri for the binary deb + string deb_uri = index->ArchiveURI(rec.FileName()); + + // now strip away the filename and add srcpkg_srcver.changelog + out_uri = flNotFile(deb_uri); + out_uri += srcpkg + "_" + srcver + ".changelog"; + return true; +} // DownloadChangelog - Download the changelog /*{{{*/ // --------------------------------------------------------------------- bool DownloadChangelog(CacheFile &CacheFile, pkgAcquire &Fetcher, pkgCache::VerIterator V, string targetfile) @@ -2775,7 +2806,18 @@ bool DownloadChangelog(CacheFile &CacheFile, pkgAcquire &Fetcher, pkgCache::VerI strprintf(path, "/changelogs/pool/%s/%s/%s/%s_%s/changelog", src_section.c_str(), prefix.c_str(), srcpkg.c_str(), srcpkg.c_str(), verstr.c_str()); // get it new pkgAcqFile(&Fetcher, server+path, "", 0, descr, srcpkg, "ignored", targetfile); + // try downloading it, if that fails, they third-party-changelogs location + // FIXME: res is "Continue" even if I get a 404?!? int res = Fetcher.Run(); + if (!FileExists(targetfile)) + { + string third_party_uri; + if (GuessThirdPartyChangelogUri(CacheFile, Pkg, V, third_party_uri)) + { + new pkgAcqFile(&Fetcher, third_party_uri, "", 0, descr, srcpkg, "ignored", targetfile); + res = Fetcher.Run(); + } + } if (FileExists(targetfile)) return true; -- cgit v1.2.3 From d786352da27c6f05bc372a061f3a78237b69e6f4 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Tue, 16 Nov 2010 10:40:36 +0100 Subject: cmdline/apt-get.cc: improve changelog description --- cmdline/apt-get.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'cmdline') diff --git a/cmdline/apt-get.cc b/cmdline/apt-get.cc index 35f37cc49..8cb43be67 100644 --- a/cmdline/apt-get.cc +++ b/cmdline/apt-get.cc @@ -2783,7 +2783,6 @@ bool DownloadChangelog(CacheFile &CacheFile, pkgAcquire &Fetcher, pkgCache::VerI // build uri srcpkg = rec.SourcePkg().empty() ? Pkg.Name() : rec.SourcePkg(); - strprintf(descr, _("Changelog for %s"), srcpkg.c_str()); // FIXME: we actually need the source section here src_section= Pkg.Section(); if(src_section.find('/')!=src_section.npos) @@ -2804,8 +2803,11 @@ bool DownloadChangelog(CacheFile &CacheFile, pkgAcquire &Fetcher, pkgCache::VerI "http://packages.debian.org/"); // ... but not the format string to avoid all possible attacks strprintf(path, "/changelogs/pool/%s/%s/%s/%s_%s/changelog", src_section.c_str(), prefix.c_str(), srcpkg.c_str(), srcpkg.c_str(), verstr.c_str()); - // get it - new pkgAcqFile(&Fetcher, server+path, "", 0, descr, srcpkg, "ignored", targetfile); + // queue it + string changelog_uri = server+path; + strprintf(descr, _("Changelog for %s (%s)"), srcpkg.c_str(), changelog_uri.c_str()); + new pkgAcqFile(&Fetcher, uri, "", 0, descr, srcpkg, "ignored", targetfile); + // try downloading it, if that fails, they third-party-changelogs location // FIXME: res is "Continue" even if I get a 404?!? int res = Fetcher.Run(); @@ -2814,6 +2816,7 @@ bool DownloadChangelog(CacheFile &CacheFile, pkgAcquire &Fetcher, pkgCache::VerI string third_party_uri; if (GuessThirdPartyChangelogUri(CacheFile, Pkg, V, third_party_uri)) { + strprintf(descr, _("Changelog for %s (%s)"), srcpkg.c_str(), third_party_uri.c_str()); new pkgAcqFile(&Fetcher, third_party_uri, "", 0, descr, srcpkg, "ignored", targetfile); res = Fetcher.Run(); } -- cgit v1.2.3