]>
git.saurik.com Git - apt.git/blob - apt-pkg/acquire-method.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: acquire-method.cc,v 1.27.2.1 2003/12/24 23:09:17 mdz Exp $
4 /* ######################################################################
8 This is a skeleton class that implements most of the functionality
9 of a method and some useful functions to make method implementation
10 simpler. The methods all derive this and specialize it. The most
11 complex implementation is the http method which needs to provide
12 pipelining, it runs the message engine at the same time it is
15 ##################################################################### */
17 // Include Files /*{{{*/
20 #include <apt-pkg/acquire-method.h>
21 #include <apt-pkg/error.h>
22 #include <apt-pkg/configuration.h>
23 #include <apt-pkg/strutl.h>
24 #include <apt-pkg/fileutl.h>
25 #include <apt-pkg/hashes.h>
26 #include <apt-pkg/md5.h>
27 #include <apt-pkg/sha1.h>
28 #include <apt-pkg/sha2.h>
42 // AcqMethod::pkgAcqMethod - Constructor /*{{{*/
43 // ---------------------------------------------------------------------
44 /* This constructs the initialization text */
45 pkgAcqMethod::pkgAcqMethod(const char *Ver
,unsigned long Flags
)
47 std::cout
<< "100 Capabilities\n"
48 << "Version: " << Ver
<< "\n";
50 if ((Flags
& SingleInstance
) == SingleInstance
)
51 std::cout
<< "Single-Instance: true\n";
53 if ((Flags
& Pipeline
) == Pipeline
)
54 std::cout
<< "Pipeline: true\n";
56 if ((Flags
& SendConfig
) == SendConfig
)
57 std::cout
<< "Send-Config: true\n";
59 if ((Flags
& LocalOnly
) == LocalOnly
)
60 std::cout
<<"Local-Only: true\n";
62 if ((Flags
& NeedsCleanup
) == NeedsCleanup
)
63 std::cout
<< "Needs-Cleanup: true\n";
65 if ((Flags
& Removable
) == Removable
)
66 std::cout
<< "Removable: true\n";
68 std::cout
<< "\n" << std::flush
;
70 SetNonBlock(STDIN_FILENO
,true);
76 // AcqMethod::Fail - A fetch has failed /*{{{*/
77 // ---------------------------------------------------------------------
79 void pkgAcqMethod::Fail(bool Transient
)
81 string Err
= "Undetermined Error";
82 if (_error
->empty() == false)
85 while (_error
->empty() == false)
88 if (_error
->PopMessage(msg
))
90 if (Err
.empty() == false)
99 // AcqMethod::Fail - A fetch has failed /*{{{*/
100 // ---------------------------------------------------------------------
102 void pkgAcqMethod::Fail(string Err
,bool Transient
)
104 // Strip out junk from the error messages
105 for (string::iterator I
= Err
.begin(); I
!= Err
.end(); ++I
)
115 std::cout
<< "400 URI Failure\nURI: " << Queue
->Uri
<< "\n"
116 << "Message: " << Err
;
117 if (IP
.empty() == false && _config
->FindB("Acquire::Failure::ShowIP", true) == true)
118 std::cout
<< " " << IP
;
123 std::cout
<< "400 URI Failure\nURI: <UNKNOWN>\nMessage: " << Err
<< "\n";
125 if(FailReason
.empty() == false)
126 std::cout
<< "FailReason: " << FailReason
<< "\n";
127 if (UsedMirror
.empty() == false)
128 std::cout
<< "UsedMirror: " << UsedMirror
<< "\n";
129 // Set the transient flag
130 if (Transient
== true)
131 std::cout
<< "Transient-Failure: true\n";
133 std::cout
<< "\n" << std::flush
;
136 // AcqMethod::DropPrivsOrDie - Drop privileges or die /*{{{*/
137 // ---------------------------------------------------------------------
139 void pkgAcqMethod::DropPrivsOrDie()
141 if (!DropPrivileges()) {
143 exit(112); /* call the european emergency number */
148 // AcqMethod::URIStart - Indicate a download is starting /*{{{*/
149 // ---------------------------------------------------------------------
151 void pkgAcqMethod::URIStart(FetchResult
&Res
)
156 std::cout
<< "200 URI Start\n"
157 << "URI: " << Queue
->Uri
<< "\n";
159 std::cout
<< "Size: " << std::to_string(Res
.Size
) << "\n";
161 if (Res
.LastModified
!= 0)
162 std::cout
<< "Last-Modified: " << TimeRFC1123(Res
.LastModified
, true) << "\n";
164 if (Res
.ResumePoint
!= 0)
165 std::cout
<< "Resume-Point: " << std::to_string(Res
.ResumePoint
) << "\n";
167 if (UsedMirror
.empty() == false)
168 std::cout
<< "UsedMirror: " << UsedMirror
<< "\n";
170 std::cout
<< "\n" << std::flush
;
173 // AcqMethod::URIDone - A URI is finished /*{{{*/
174 // ---------------------------------------------------------------------
176 static void printHashStringList(HashStringList
const * const list
)
178 for (HashStringList::const_iterator hash
= list
->begin(); hash
!= list
->end(); ++hash
)
180 // very old compatibility name for MD5Sum
181 if (hash
->HashType() == "MD5Sum")
182 std::cout
<< "MD5-Hash: " << hash
->HashValue() << "\n";
183 std::cout
<< hash
->HashType() << "-Hash: " << hash
->HashValue() << "\n";
186 void pkgAcqMethod::URIDone(FetchResult
&Res
, FetchResult
*Alt
)
191 std::cout
<< "201 URI Done\n"
192 << "URI: " << Queue
->Uri
<< "\n";
194 if (Res
.Filename
.empty() == false)
195 std::cout
<< "Filename: " << Res
.Filename
<< "\n";
198 std::cout
<< "Size: " << std::to_string(Res
.Size
) << "\n";
200 if (Res
.LastModified
!= 0)
201 std::cout
<< "Last-Modified: " << TimeRFC1123(Res
.LastModified
, true) << "\n";
203 printHashStringList(&Res
.Hashes
);
205 if (UsedMirror
.empty() == false)
206 std::cout
<< "UsedMirror: " << UsedMirror
<< "\n";
207 if (Res
.GPGVOutput
.empty() == false)
209 std::cout
<< "GPGVOutput:\n";
210 for (vector
<string
>::const_iterator I
= Res
.GPGVOutput
.begin();
211 I
!= Res
.GPGVOutput
.end(); ++I
)
212 std::cout
<< " " << *I
<< "\n";
215 if (Res
.ResumePoint
!= 0)
216 std::cout
<< "Resume-Point: " << std::to_string(Res
.ResumePoint
) << "\n";
218 if (Res
.IMSHit
== true)
219 std::cout
<< "IMS-Hit: true\n";
223 if (Alt
->Filename
.empty() == false)
224 std::cout
<< "Alt-Filename: " << Alt
->Filename
<< "\n";
227 std::cout
<< "Alt-Size: " << std::to_string(Alt
->Size
) << "\n";
229 if (Alt
->LastModified
!= 0)
230 std::cout
<< "Alt-Last-Modified: " << TimeRFC1123(Alt
->LastModified
, true) << "\n";
232 printHashStringList(&Alt
->Hashes
);
234 if (Alt
->IMSHit
== true)
235 std::cout
<< "Alt-IMS-Hit: true\n";
238 std::cout
<< "\n" << std::flush
;
242 // AcqMethod::MediaFail - Syncronous request for new media /*{{{*/
243 // ---------------------------------------------------------------------
244 /* This sends a 403 Media Failure message to the APT and waits for it
246 bool pkgAcqMethod::MediaFail(string Required
,string Drive
)
248 fprintf(stdout
, "403 Media Failure\nMedia: %s\nDrive: %s\n",
249 Required
.c_str(),Drive
.c_str());
250 std::cout
<< "\n" << std::flush
;
252 vector
<string
> MyMessages
;
254 /* Here we read messages until we find a 603, each non 603 message is
255 appended to the main message list for later processing */
258 if (WaitFd(STDIN_FILENO
) == false)
261 if (ReadMessages(STDIN_FILENO
,MyMessages
) == false)
264 string Message
= MyMessages
.front();
265 MyMessages
.erase(MyMessages
.begin());
267 // Fetch the message number
269 int Number
= strtol(Message
.c_str(),&End
,10);
270 if (End
== Message
.c_str())
272 cerr
<< "Malformed message!" << endl
;
279 while (MyMessages
.empty() == false)
281 Messages
.push_back(MyMessages
.front());
282 MyMessages
.erase(MyMessages
.begin());
285 return !StringToBool(LookupTag(Message
,"Failed"),false);
288 Messages
.push_back(Message
);
292 // AcqMethod::Configuration - Handle the configuration message /*{{{*/
293 // ---------------------------------------------------------------------
294 /* This parses each configuration entry and puts it into the _config
295 Configuration class. */
296 bool pkgAcqMethod::Configuration(string Message
)
298 ::Configuration
&Cnf
= *_config
;
300 const char *I
= Message
.c_str();
301 const char *MsgEnd
= I
+ Message
.length();
303 unsigned int Length
= strlen("Config-Item");
304 for (; I
+ Length
< MsgEnd
; I
++)
307 if (I
[Length
] != ':' || stringcasecmp(I
,I
+Length
,"Config-Item") != 0)
312 for (; I
< MsgEnd
&& *I
== ' '; I
++);
313 const char *Equals
= (const char*) memchr(I
, '=', MsgEnd
- I
);
316 const char *End
= (const char*) memchr(Equals
, '\n', MsgEnd
- Equals
);
320 Cnf
.Set(DeQuoteString(string(I
,Equals
-I
)),
321 DeQuoteString(string(Equals
+1,End
-Equals
-1)));
328 // AcqMethod::Run - Run the message engine /*{{{*/
329 // ---------------------------------------------------------------------
330 /* Fetch any messages and execute them. In single mode it returns 1 if
331 there are no more available messages - any other result is a
332 fatal failure code! */
333 int pkgAcqMethod::Run(bool Single
)
337 // Block if the message queue is empty
338 if (Messages
.empty() == true)
341 if (WaitFd(STDIN_FILENO
) == false)
343 if (ReadMessages(STDIN_FILENO
,Messages
) == false)
347 // Single mode exits if the message queue is empty
348 if (Single
== true && Messages
.empty() == true)
351 string Message
= Messages
.front();
352 Messages
.erase(Messages
.begin());
354 // Fetch the message number
356 int Number
= strtol(Message
.c_str(),&End
,10);
357 if (End
== Message
.c_str())
359 cerr
<< "Malformed message!" << endl
;
366 if (Configuration(Message
) == false)
372 FetchItem
*Tmp
= new FetchItem
;
374 Tmp
->Uri
= LookupTag(Message
,"URI");
375 Tmp
->DestFile
= LookupTag(Message
,"FileName");
376 if (RFC1123StrToTime(LookupTag(Message
,"Last-Modified").c_str(),Tmp
->LastModified
) == false)
377 Tmp
->LastModified
= 0;
378 Tmp
->IndexFile
= StringToBool(LookupTag(Message
,"Index-File"),false);
379 Tmp
->FailIgnore
= StringToBool(LookupTag(Message
,"Fail-Ignore"),false);
380 Tmp
->ExpectedHashes
= HashStringList();
381 for (char const * const * t
= HashString::SupportedHashes(); *t
!= NULL
; ++t
)
383 std::string tag
= "Expected-";
385 std::string
const hash
= LookupTag(Message
, tag
.c_str());
386 if (hash
.empty() == false)
387 Tmp
->ExpectedHashes
.push_back(HashString(*t
, hash
));
390 if (Tmp
->ExpectedHashes
.FileSize() > 0)
391 Tmp
->MaximumSize
= Tmp
->ExpectedHashes
.FileSize();
393 Tmp
->MaximumSize
= strtoll(LookupTag(Message
, "Maximum-Size", "0").c_str(), &End
, 10);
396 // Append it to the list
397 FetchItem
**I
= &Queue
;
398 for (; *I
!= 0; I
= &(*I
)->Next
);
403 // Notify that this item is to be fetched.
404 if (URIAcquire(Message
, Tmp
) == false)
416 // AcqMethod::PrintStatus - privately really send a log/status message /*{{{*/
417 void pkgAcqMethod::PrintStatus(char const * const header
, const char* Format
,
420 string CurrentURI
= "<UNKNOWN>";
422 CurrentURI
= Queue
->Uri
;
423 if (UsedMirror
.empty() == true)
424 fprintf(stdout
, "%s\nURI: %s\nMessage: ",
425 header
, CurrentURI
.c_str());
427 fprintf(stdout
, "%s\nURI: %s\nUsedMirror: %s\nMessage: ",
428 header
, CurrentURI
.c_str(), UsedMirror
.c_str());
429 vfprintf(stdout
,Format
,args
);
430 std::cout
<< "\n\n" << std::flush
;
433 // AcqMethod::Log - Send a log message /*{{{*/
434 // ---------------------------------------------------------------------
436 void pkgAcqMethod::Log(const char *Format
,...)
439 va_start(args
,Format
);
440 PrintStatus("101 Log", Format
, args
);
444 // AcqMethod::Status - Send a status message /*{{{*/
445 // ---------------------------------------------------------------------
447 void pkgAcqMethod::Status(const char *Format
,...)
450 va_start(args
,Format
);
451 PrintStatus("102 Status", Format
, args
);
455 // AcqMethod::Redirect - Send a redirect message /*{{{*/
456 // ---------------------------------------------------------------------
457 /* This method sends the redirect message and dequeues the item as
458 * the worker will enqueue again later on to the right queue */
459 void pkgAcqMethod::Redirect(const string
&NewURI
)
461 std::cout
<< "103 Redirect\nURI: " << Queue
->Uri
<< "\n"
462 << "New-URI: " << NewURI
<< "\n"
463 << "\n" << std::flush
;
467 // AcqMethod::FetchResult::FetchResult - Constructor /*{{{*/
468 // ---------------------------------------------------------------------
470 pkgAcqMethod::FetchResult::FetchResult() : LastModified(0),
471 IMSHit(false), Size(0), ResumePoint(0), d(NULL
)
475 // AcqMethod::FetchResult::TakeHashes - Load hashes /*{{{*/
476 // ---------------------------------------------------------------------
477 /* This hides the number of hashes we are supporting from the caller.
478 It just deals with the hash class. */
479 void pkgAcqMethod::FetchResult::TakeHashes(class Hashes
&Hash
)
481 Hashes
= Hash
.GetHashStringList();
484 void pkgAcqMethod::Dequeue() { /*{{{*/
485 FetchItem
const * const Tmp
= Queue
;
487 if (Tmp
== QueueBack
)
492 pkgAcqMethod::~pkgAcqMethod() {}
494 pkgAcqMethod::FetchItem::FetchItem() :
495 Next(nullptr), DestFileFd(-1), LastModified(0), IndexFile(false),
496 FailIgnore(false), MaximumSize(0), d(nullptr)
498 pkgAcqMethod::FetchItem::~FetchItem() {}
500 pkgAcqMethod::FetchResult::~FetchResult() {}