From 09fab2442c2ab9a503841d3dcd56b3c0c3efb502 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Thu, 9 Apr 2009 04:36:34 +0200 Subject: * apt-pkg/contrib/strutl.cc: - fix TimeToStr i18n (LP: #289807) * [ABI break] merge support for http redirects, thanks to Jeff Licquia and Anthony Towns * [ABI break] use int for the package IDs (thanks to Steve Cotton) * apt-pkg/pkgcache.cc: - do not run "dpkg --configure pkg" if pkg is in trigger-awaited state (LP: #322955) * methods/https.cc: - add Acquire::https::AllowRedirect support * Clarify the --help for 'purge' (LP: #243948) * cmdline/apt-get.cc - fix "apt-get source pkg" if there is a binary package and a source package of the same name but from different packages (LP: #330103) * cmdline/acqprogress.cc: - Call pkgAcquireStatus::Pulse even if quiet, so that we still get dlstatus messages on the status-fd (LP: #290234). --- .bzr-builddeb/default.conf | 5 +++ .bzr-builddeb/default.conf.orig | 2 ++ apt-pkg/acquire-method.cc | 32 +++++++++++++++++ apt-pkg/acquire-method.h | 2 ++ apt-pkg/acquire-worker.cc | 14 ++++++++ apt-pkg/contrib/strutl.cc | 14 +++++--- apt-pkg/deb/debsystem.cc | 2 +- apt-pkg/deb/dpkgpm.cc | 4 +-- apt-pkg/makefile | 2 +- apt-pkg/pkgcache.cc | 8 +++-- apt-pkg/pkgcache.h | 8 ++--- cmdline/acqprogress.cc | 4 +-- cmdline/apt-get.cc | 25 +++++++------ debian/changelog | 20 +++++++++++ doc/examples/configure-index | 6 ++-- ftparchive/cachedb.cc | 1 + methods/http.cc | 78 ++++++++++++++++++++++++++++++++++++++++- methods/http.h | 3 ++ methods/https.cc | 6 +++- methods/makefile | 2 +- pre-build.sh | 3 ++ 21 files changed, 208 insertions(+), 33 deletions(-) create mode 100644 .bzr-builddeb/default.conf create mode 100644 .bzr-builddeb/default.conf.orig create mode 100755 pre-build.sh diff --git a/.bzr-builddeb/default.conf b/.bzr-builddeb/default.conf new file mode 100644 index 000000000..f2c082569 --- /dev/null +++ b/.bzr-builddeb/default.conf @@ -0,0 +1,5 @@ +[BUILDDEB] +native = true + +[HOOKS] +pre-build=./pre-build.sh diff --git a/.bzr-builddeb/default.conf.orig b/.bzr-builddeb/default.conf.orig new file mode 100644 index 000000000..9c55498ce --- /dev/null +++ b/.bzr-builddeb/default.conf.orig @@ -0,0 +1,2 @@ +[BUILDDEB] +native = true diff --git a/apt-pkg/acquire-method.cc b/apt-pkg/acquire-method.cc index bc29417f7..acf1156dc 100644 --- a/apt-pkg/acquire-method.cc +++ b/apt-pkg/acquire-method.cc @@ -447,6 +447,38 @@ void pkgAcqMethod::Status(const char *Format,...) } /*}}}*/ +// AcqMethod::Redirect - Send a redirect message /*{{{*/ +// --------------------------------------------------------------------- +/* This method sends the redirect message and also manipulates the queue + to keep the pipeline synchronized. */ +void pkgAcqMethod::Redirect(const string &NewURI) +{ + string CurrentURI = ""; + if (Queue != 0) + CurrentURI = Queue->Uri; + + char S[1024]; + snprintf(S, sizeof(S)-50, "103 Redirect\nURI: %s\nNew-URI: %s\n\n", + CurrentURI.c_str(), NewURI.c_str()); + + if (write(STDOUT_FILENO,S,strlen(S)) != (ssize_t)strlen(S)) + exit(100); + + // Change the URI for the request. + Queue->Uri = NewURI; + + /* To keep the pipeline synchronized, move the current request to + the end of the queue, past the end of the current pipeline. */ + FetchItem *I; + for (I = Queue; I->Next != 0; I = I->Next) ; + I->Next = Queue; + Queue = Queue->Next; + I->Next->Next = 0; + if (QueueBack == 0) + QueueBack = I->Next; +} + /*}}}*/ + // AcqMethod::FetchResult::FetchResult - Constructor /*{{{*/ // --------------------------------------------------------------------- /* */ diff --git a/apt-pkg/acquire-method.h b/apt-pkg/acquire-method.h index e02eab018..fab77e664 100644 --- a/apt-pkg/acquire-method.h +++ b/apt-pkg/acquire-method.h @@ -84,6 +84,8 @@ class pkgAcqMethod void Log(const char *Format,...); void Status(const char *Format,...); + void Redirect(const string &NewURI); + int Run(bool Single = false); inline void SetFailExtraMsg(string Msg) {FailExtra = Msg;}; diff --git a/apt-pkg/acquire-worker.cc b/apt-pkg/acquire-worker.cc index 1a754dae9..78c68737c 100644 --- a/apt-pkg/acquire-worker.cc +++ b/apt-pkg/acquire-worker.cc @@ -220,6 +220,20 @@ bool pkgAcquire::Worker::RunMessages() Status = LookupTag(Message,"Message"); break; + // 103 Redirect + case 103: + { + if (Itm == 0) + { + _error->Error("Method gave invalid 103 Redirect message"); + break; + } + + string NewURI = LookupTag(Message,"New-URI",URI.c_str()); + Itm->URI = NewURI; + break; + } + // 200 URI Start case 200: { diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc index bd374fd1e..a69cf01ec 100644 --- a/apt-pkg/contrib/strutl.cc +++ b/apt-pkg/contrib/strutl.cc @@ -331,23 +331,27 @@ string TimeToStr(unsigned long Sec) { if (Sec > 60*60*24) { - sprintf(S,"%lid %lih%limin%lis",Sec/60/60/24,(Sec/60/60) % 24,(Sec/60) % 60,Sec % 60); + //d means days, h means hours, min means minutes, s means seconds + sprintf(S,_("%lid %lih %limin %lis"),Sec/60/60/24,(Sec/60/60) % 24,(Sec/60) % 60,Sec % 60); break; } if (Sec > 60*60) { - sprintf(S,"%lih%limin%lis",Sec/60/60,(Sec/60) % 60,Sec % 60); + //h means hours, min means minutes, s means seconds + sprintf(S,_("%lih %limin %lis"),Sec/60/60,(Sec/60) % 60,Sec % 60); break; } if (Sec > 60) { - sprintf(S,"%limin%lis",Sec/60,Sec % 60); + //min means minutes, s means seconds + sprintf(S,_("%limin %lis"),Sec/60,Sec % 60); break; } - - sprintf(S,"%lis",Sec); + + //s means seconds + sprintf(S,_("%lis"),Sec); break; } diff --git a/apt-pkg/deb/debsystem.cc b/apt-pkg/deb/debsystem.cc index 11a84f1c6..baa98f546 100644 --- a/apt-pkg/deb/debsystem.cc +++ b/apt-pkg/deb/debsystem.cc @@ -96,7 +96,7 @@ bool debSystem::UnLock(bool NoErrors) return false; if (LockCount < 1) - return _error->Error("Not locked"); + return _error->Error(_("Not locked")); if (--LockCount == 0) { close(LockFD); diff --git a/apt-pkg/deb/dpkgpm.cc b/apt-pkg/deb/dpkgpm.cc index 40aafafa4..85e54988e 100644 --- a/apt-pkg/deb/dpkgpm.cc +++ b/apt-pkg/deb/dpkgpm.cc @@ -777,16 +777,14 @@ bool pkgDPkgPM::Go(int OutStatusFd) sighandler_t old_SIGHUP = signal(SIGHUP,SIG_IGN); struct termios tt; - struct termios tt_out; struct winsize win; int master; int slave; // FIXME: setup sensible signal handling (*ick*) tcgetattr(0, &tt); - tcgetattr(1, &tt_out); ioctl(0, TIOCGWINSZ, (char *)&win); - if (openpty(&master, &slave, NULL, &tt_out, &win) < 0) + if (openpty(&master, &slave, NULL, &tt, &win) < 0) { const char *s = _("Can not write log, openpty() " "failed (/dev/pts not mounted?)\n"); diff --git a/apt-pkg/makefile b/apt-pkg/makefile index 1b78c94f6..087f17740 100644 --- a/apt-pkg/makefile +++ b/apt-pkg/makefile @@ -13,7 +13,7 @@ include ../buildlib/defaults.mak # methods/makefile - FIXME LIBRARY=apt-pkg LIBEXT=$(GLIBC_VER)$(LIBSTDCPP_VER) -MAJOR=4.6 +MAJOR=4.7 MINOR=0 SLIBS=$(PTHREADLIB) $(INTLLIBS) -lutil APT_DOMAIN:=libapt-pkg$(MAJOR) diff --git a/apt-pkg/pkgcache.cc b/apt-pkg/pkgcache.cc index 8eb62089a..4fbf42c4b 100644 --- a/apt-pkg/pkgcache.cc +++ b/apt-pkg/pkgcache.cc @@ -275,8 +275,12 @@ pkgCache::PkgIterator::OkState pkgCache::PkgIterator::State() const if (Pkg->CurrentState == pkgCache::State::UnPacked || Pkg->CurrentState == pkgCache::State::HalfConfigured || - Pkg->CurrentState == pkgCache::State::TriggersPending || - Pkg->CurrentState == pkgCache::State::TriggersAwaited) + //we don't need to care for triggers awaiting packages + //dpkg will deal with them automatically when the + //trigger pending action is run (those packages are usually + //in half-configured or triggers-pending state) + //Pkg->CurrentState == pkgCache::State::TriggersAwaited + Pkg->CurrentState == pkgCache::State::TriggersPending) return NeedsConfigure; if (Pkg->CurrentState == pkgCache::State::HalfInstalled || diff --git a/apt-pkg/pkgcache.h b/apt-pkg/pkgcache.h index 59d5003bb..759e9a225 100644 --- a/apt-pkg/pkgcache.h +++ b/apt-pkg/pkgcache.h @@ -214,7 +214,7 @@ struct pkgCache::Package unsigned char InstState; // Flags unsigned char CurrentState; // State - unsigned short ID; + unsigned int ID; unsigned long Flags; }; @@ -235,7 +235,7 @@ struct pkgCache::PackageFile // Linked list map_ptrloc NextFile; // PackageFile - unsigned short ID; + unsigned int ID; time_t mtime; // Modification time for the file }; @@ -272,7 +272,7 @@ struct pkgCache::Version map_ptrloc Size; // These are the .deb size map_ptrloc InstalledSize; unsigned short Hash; - unsigned short ID; + unsigned int ID; unsigned char Priority; }; @@ -289,7 +289,7 @@ struct pkgCache::Description map_ptrloc NextDesc; // Description map_ptrloc ParentPkg; // Package - unsigned short ID; + unsigned int ID; }; struct pkgCache::Dependency diff --git a/cmdline/acqprogress.cc b/cmdline/acqprogress.cc index a5fee1db5..b3ded4142 100644 --- a/cmdline/acqprogress.cc +++ b/cmdline/acqprogress.cc @@ -145,11 +145,11 @@ void AcqTextStatus::Stop() bandwidth and ETA indicator. */ bool AcqTextStatus::Pulse(pkgAcquire *Owner) { + pkgAcquireStatus::Pulse(Owner); + if (Quiet > 0) return true; - pkgAcquireStatus::Pulse(Owner); - enum {Long = 0,Medium,Short} Mode = Long; char Buffer[sizeof(BlankLine)]; diff --git a/cmdline/apt-get.cc b/cmdline/apt-get.cc index a7221d47d..ccf53ed25 100644 --- a/cmdline/apt-get.cc +++ b/cmdline/apt-get.cc @@ -1272,16 +1272,23 @@ pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs, } } } - - // No source package name.. - if (Src.empty() == true) - Src = TmpSrc; - + // The best hit pkgSrcRecords::Parser *Last = 0; unsigned long Offset = 0; string Version; bool IsMatch = false; + bool MatchSrcOnly = false; + + // No source package name.. + if (Src.empty() == true) + Src = TmpSrc; + else + // if we have a source pkg name, make sure to only search + // for srcpkg names, otherwise apt gets confused if there + // is a binary package "pkg1" and a source package "pkg1" + // with the same name but that comes from different packages + MatchSrcOnly = true; // If we are matching by version then we need exact matches to be happy if (VerTag.empty() == false) @@ -1291,13 +1298,11 @@ pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs, binary packages in the search */ pkgSrcRecords::Parser *Parse; SrcRecs.Restart(); - while ((Parse = SrcRecs.Find(Src.c_str(),false)) != 0) + while ((Parse = SrcRecs.Find(Src.c_str(), MatchSrcOnly)) != 0) { string Ver = Parse->Version(); - // Skip name mismatches - if (IsMatch == true && Parse->Package() != Src) - continue; + ioprintf(c1out, _("No source package '%s' picking '%s' instead\n"), Parse->Package().c_str(), Src.c_str()); if (VerTag.empty() == false) { @@ -2632,7 +2637,7 @@ bool ShowHelp(CommandLine &CmdL) " install - Install new packages (pkg is libc6 not libc6.deb)\n" " remove - Remove packages\n" " autoremove - Remove automatically all unused packages\n" - " purge - Remove and purge packages\n" + " purge - Remove packages and config files\n" " source - Download source archives\n" " build-dep - Configure build-dependencies for source packages\n" " dist-upgrade - Distribution upgrade, see apt-get(8)\n" diff --git a/debian/changelog b/debian/changelog index 5ddd98a0d..6fe3b7a70 100644 --- a/debian/changelog +++ b/debian/changelog @@ -18,6 +18,26 @@ apt (0.7.20.3) UNRELEASED; urgency=low [ Michael Vogt ] * methods/gpgv.cc: - properly check for expired and revoked keys (closes: #433091) + * apt-pkg/contrib/strutl.cc: + - fix TimeToStr i18n (LP: #289807) + * [ABI break] merge support for http redirects, thanks to + Jeff Licquia and Anthony Towns + * [ABI break] use int for the package IDs (thanks to Steve Cotton) + * apt-pkg/pkgcache.cc: + - do not run "dpkg --configure pkg" if pkg is in trigger-awaited + state (LP: #322955) + * methods/https.cc: + - add Acquire::https::AllowRedirect support + * Clarify the --help for 'purge' (LP: #243948) + * cmdline/apt-get.cc + - fix "apt-get source pkg" if there is a binary package and + a source package of the same name but from different + packages (LP: #330103) + + [ Colin Watson ] + * cmdline/acqprogress.cc: + - Call pkgAcquireStatus::Pulse even if quiet, so that we still get + dlstatus messages on the status-fd (LP: #290234). -- Michael Vogt Wed, 08 Apr 2009 22:37:01 +0200 diff --git a/doc/examples/configure-index b/doc/examples/configure-index index db07f189e..5f29a2d3f 100644 --- a/doc/examples/configure-index +++ b/doc/examples/configure-index @@ -133,7 +133,8 @@ Acquire Proxy::http.us.debian.org "DIRECT"; // Specific per-host setting Timeout "120"; Pipeline-Depth "5"; - + AllowRedirect "true"; + // Cache Control. Note these do not work with Squid 2.0.2 No-Cache "false"; Max-Age "86400"; // 1 Day age on index files @@ -150,7 +151,8 @@ Acquire Verify-Peer "false"; SslCert "/etc/apt/some.pem"; CaPath "/etc/ssl/certs"; - Verify-Host" "2"; + Verify-Host" "true"; + AllowRedirect "true"; }; ftp diff --git a/ftparchive/cachedb.cc b/ftparchive/cachedb.cc index 8de3a0b9e..ff9a92d32 100644 --- a/ftparchive/cachedb.cc +++ b/ftparchive/cachedb.cc @@ -463,6 +463,7 @@ bool CacheDB::Clean() Cursor->c_del(Cursor,0); } + Dbp->compact(Dbp, NULL, NULL, NULL, NULL, DB_FREE_SPACE, NULL); return true; } diff --git a/methods/http.cc b/methods/http.cc index b3c791fa0..1bf798da4 100644 --- a/methods/http.cc +++ b/methods/http.cc @@ -39,6 +39,7 @@ #include #include #include +#include #include // Internet stuff @@ -57,6 +58,7 @@ int HttpMethod::FailFd = -1; time_t HttpMethod::FailTime = 0; unsigned long PipelineDepth = 10; unsigned long TimeOut = 120; +bool AllowRedirect = false; bool Debug = false; URI Proxy; @@ -628,6 +630,12 @@ bool ServerState::HeaderLine(string Line) return true; } + if (stringcasecmp(Tag,"Location:") == 0) + { + Location = Val; + return true; + } + return true; } /*}}}*/ @@ -900,7 +908,9 @@ bool HttpMethod::ServerDie(ServerState *Srv) 1 - IMS hit 3 - Unrecoverable error 4 - Error with error content page - 5 - Unrecoverable non-server error (close the connection) */ + 5 - Unrecoverable non-server error (close the connection) + 6 - Try again with a new or changed URI + */ int HttpMethod::DealWithHeaders(FetchResult &Res,ServerState *Srv) { // Not Modified @@ -912,6 +922,27 @@ int HttpMethod::DealWithHeaders(FetchResult &Res,ServerState *Srv) return 1; } + /* Redirect + * + * Note that it is only OK for us to treat all redirection the same + * because we *always* use GET, not other HTTP methods. There are + * three redirection codes for which it is not appropriate that we + * redirect. Pass on those codes so the error handling kicks in. + */ + if (AllowRedirect + && (Srv->Result > 300 && Srv->Result < 400) + && (Srv->Result != 300 // Multiple Choices + && Srv->Result != 304 // Not Modified + && Srv->Result != 306)) // (Not part of HTTP/1.1, reserved) + { + if (!Srv->Location.empty()) + { + NextURI = Srv->Location; + return 6; + } + /* else pass through for error message */ + } + /* We have a reply we dont handle. This should indicate a perm server failure */ if (Srv->Result < 200 || Srv->Result >= 300) @@ -1026,6 +1057,7 @@ bool HttpMethod::Configuration(string Message) if (pkgAcqMethod::Configuration(Message) == false) return false; + AllowRedirect = _config->FindB("Acquire::http::AllowRedirect",true); TimeOut = _config->FindI("Acquire::http::Timeout",TimeOut); PipelineDepth = _config->FindI("Acquire::http::Pipeline-Depth", PipelineDepth); @@ -1039,6 +1071,10 @@ bool HttpMethod::Configuration(string Message) /* */ int HttpMethod::Loop() { + typedef vector StringVector; + typedef vector::iterator StringVectorIterator; + map Redirected; + signal(SIGTERM,SigTerm); signal(SIGINT,SigTerm); @@ -1225,6 +1261,46 @@ int HttpMethod::Loop() break; } + // Try again with a new URL + case 6: + { + // Clear rest of response if there is content + if (Server->HaveContent) + { + File = new FileFd("/dev/null",FileFd::WriteExists); + Server->RunData(); + delete File; + File = 0; + } + + /* Detect redirect loops. No more redirects are allowed + after the same URI is seen twice in a queue item. */ + StringVector &R = Redirected[Queue->DestFile]; + bool StopRedirects = false; + if (R.size() == 0) + R.push_back(Queue->Uri); + else if (R[0] == "STOP" || R.size() > 10) + StopRedirects = true; + else + { + for (StringVectorIterator I = R.begin(); I != R.end(); I++) + if (Queue->Uri == *I) + { + R[0] = "STOP"; + break; + } + + R.push_back(Queue->Uri); + } + + if (StopRedirects == false) + Redirect(NextURI); + else + Fail(); + + break; + } + default: Fail(_("Internal error")); break; diff --git a/methods/http.h b/methods/http.h index 6753a9901..13f02ec77 100644 --- a/methods/http.h +++ b/methods/http.h @@ -99,6 +99,7 @@ struct ServerState enum {Chunked,Stream,Closes} Encoding; enum {Header, Data} State; bool Persistent; + string Location; // This is a Persistent attribute of the server itself. bool Pipeline; @@ -143,6 +144,8 @@ class HttpMethod : public pkgAcqMethod static time_t FailTime; static void SigTerm(int); + string NextURI; + public: friend class ServerState; diff --git a/methods/https.cc b/methods/https.cc index 98dfeefa1..8bf44b52a 100644 --- a/methods/https.cc +++ b/methods/https.cc @@ -208,6 +208,11 @@ bool HttpsMethod::Fetch(FetchItem *Itm) curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout); curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, timeout); + // set redirect options and default to 10 redirects + bool AllowRedirect = _config->FindI("Acquire::https::AllowRedirect", true); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, AllowRedirect); + curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 10); + // debug if(_config->FindB("Debug::Acquire::https", false)) curl_easy_setopt(curl, CURLOPT_VERBOSE, true); @@ -248,7 +253,6 @@ bool HttpsMethod::Fetch(FetchItem *Itm) // cleanup if(success != 0) { - unlink(File->Name().c_str()); _error->Error("%s", curl_errorstr); Fail(); return true; diff --git a/methods/makefile b/methods/makefile index d9481dbcc..78bdbc96f 100644 --- a/methods/makefile +++ b/methods/makefile @@ -7,7 +7,7 @@ include ../buildlib/defaults.mak BIN := $(BIN)/methods # FIXME.. -LIB_APT_PKG_MAJOR = 4.6 +LIB_APT_PKG_MAJOR = 4.7 APT_DOMAIN := libapt-pkg$(LIB_APT_PKG_MAJOR) # The file method diff --git a/pre-build.sh b/pre-build.sh new file mode 100755 index 000000000..2c7d28c2c --- /dev/null +++ b/pre-build.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +make -f Makefile startup doc -- cgit v1.2.3