]>
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)
83 _error
->PopMessage(Err
);
88 // AcqMethod::Fail - A fetch has failed /*{{{*/
89 // ---------------------------------------------------------------------
91 void pkgAcqMethod::Fail(string Err
,bool Transient
)
93 // Strip out junk from the error messages
94 for (string::iterator I
= Err
.begin(); I
!= Err
.end(); ++I
)
104 std::cout
<< "400 URI Failure\nURI: " << Queue
->Uri
<< "\n"
105 << "Message: " << Err
;
106 if (IP
.empty() == false && _config
->FindB("Acquire::Failure::ShowIP", true) == true)
107 std::cout
<< " " << IP
;
112 std::cout
<< "400 URI Failure\nURI: <UNKNOWN>\nMessage: " << Err
<< "\n";
114 if(FailReason
.empty() == false)
115 std::cout
<< "FailReason: " << FailReason
<< "\n";
116 if (UsedMirror
.empty() == false)
117 std::cout
<< "UsedMirror: " << UsedMirror
<< "\n";
118 // Set the transient flag
119 if (Transient
== true)
120 std::cout
<< "Transient-Failure: true\n";
122 std::cout
<< "\n" << std::flush
;
125 // AcqMethod::DropPrivsOrDie - Drop privileges or die /*{{{*/
126 // ---------------------------------------------------------------------
128 void pkgAcqMethod::DropPrivsOrDie()
130 if (!DropPrivileges()) {
132 exit(112); /* call the european emergency number */
137 // AcqMethod::URIStart - Indicate a download is starting /*{{{*/
138 // ---------------------------------------------------------------------
140 void pkgAcqMethod::URIStart(FetchResult
&Res
)
145 std::cout
<< "200 URI Start\n"
146 << "URI: " << Queue
->Uri
<< "\n";
148 std::cout
<< "Size: " << Res
.Size
<< "\n";
150 if (Res
.LastModified
!= 0)
151 std::cout
<< "Last-Modified: " << TimeRFC1123(Res
.LastModified
) << "\n";
153 if (Res
.ResumePoint
!= 0)
154 std::cout
<< "Resume-Point: " << Res
.ResumePoint
<< "\n";
156 if (UsedMirror
.empty() == false)
157 std::cout
<< "UsedMirror: " << UsedMirror
<< "\n";
159 std::cout
<< "\n" << std::flush
;
162 // AcqMethod::URIDone - A URI is finished /*{{{*/
163 // ---------------------------------------------------------------------
165 static void printHashStringList(HashStringList
const * const list
)
167 for (HashStringList::const_iterator hash
= list
->begin(); hash
!= list
->end(); ++hash
)
169 // very old compatibility name for MD5Sum
170 if (hash
->HashType() == "MD5Sum")
171 std::cout
<< "MD5-Hash: " << hash
->HashValue() << "\n";
172 std::cout
<< hash
->HashType() << "-Hash: " << hash
->HashValue() << "\n";
175 void pkgAcqMethod::URIDone(FetchResult
&Res
, FetchResult
*Alt
)
180 std::cout
<< "201 URI Done\n"
181 << "URI: " << Queue
->Uri
<< "\n";
183 if (Res
.Filename
.empty() == false)
184 std::cout
<< "Filename: " << Res
.Filename
<< "\n";
187 std::cout
<< "Size: " << Res
.Size
<< "\n";
189 if (Res
.LastModified
!= 0)
190 std::cout
<< "Last-Modified: " << TimeRFC1123(Res
.LastModified
) << "\n";
192 printHashStringList(&Res
.Hashes
);
194 if (UsedMirror
.empty() == false)
195 std::cout
<< "UsedMirror: " << UsedMirror
<< "\n";
196 if (Res
.GPGVOutput
.empty() == false)
198 std::cout
<< "GPGVOutput:\n";
199 for (vector
<string
>::const_iterator I
= Res
.GPGVOutput
.begin();
200 I
!= Res
.GPGVOutput
.end(); ++I
)
201 std::cout
<< " " << *I
<< "\n";
204 if (Res
.ResumePoint
!= 0)
205 std::cout
<< "Resume-Point: " << Res
.ResumePoint
<< "\n";
207 if (Res
.IMSHit
== true)
208 std::cout
<< "IMS-Hit: true\n";
212 if (Alt
->Filename
.empty() == false)
213 std::cout
<< "Alt-Filename: " << Alt
->Filename
<< "\n";
216 std::cout
<< "Alt-Size: " << Alt
->Size
<< "\n";
218 if (Alt
->LastModified
!= 0)
219 std::cout
<< "Alt-Last-Modified: " << TimeRFC1123(Alt
->LastModified
) << "\n";
221 printHashStringList(&Alt
->Hashes
);
223 if (Alt
->IMSHit
== true)
224 std::cout
<< "Alt-IMS-Hit: true\n";
227 std::cout
<< "\n" << std::flush
;
231 // AcqMethod::MediaFail - Syncronous request for new media /*{{{*/
232 // ---------------------------------------------------------------------
233 /* This sends a 403 Media Failure message to the APT and waits for it
235 bool pkgAcqMethod::MediaFail(string Required
,string Drive
)
237 fprintf(stdout
, "403 Media Failure\nMedia: %s\nDrive: %s\n",
238 Required
.c_str(),Drive
.c_str());
239 std::cout
<< "\n" << std::flush
;
241 vector
<string
> MyMessages
;
243 /* Here we read messages until we find a 603, each non 603 message is
244 appended to the main message list for later processing */
247 if (WaitFd(STDIN_FILENO
) == false)
250 if (ReadMessages(STDIN_FILENO
,MyMessages
) == false)
253 string Message
= MyMessages
.front();
254 MyMessages
.erase(MyMessages
.begin());
256 // Fetch the message number
258 int Number
= strtol(Message
.c_str(),&End
,10);
259 if (End
== Message
.c_str())
261 cerr
<< "Malformed message!" << endl
;
268 while (MyMessages
.empty() == false)
270 Messages
.push_back(MyMessages
.front());
271 MyMessages
.erase(MyMessages
.begin());
274 return !StringToBool(LookupTag(Message
,"Failed"),false);
277 Messages
.push_back(Message
);
281 // AcqMethod::Configuration - Handle the configuration message /*{{{*/
282 // ---------------------------------------------------------------------
283 /* This parses each configuration entry and puts it into the _config
284 Configuration class. */
285 bool pkgAcqMethod::Configuration(string Message
)
287 ::Configuration
&Cnf
= *_config
;
289 const char *I
= Message
.c_str();
290 const char *MsgEnd
= I
+ Message
.length();
292 unsigned int Length
= strlen("Config-Item");
293 for (; I
+ Length
< MsgEnd
; I
++)
296 if (I
[Length
] != ':' || stringcasecmp(I
,I
+Length
,"Config-Item") != 0)
301 for (; I
< MsgEnd
&& *I
== ' '; I
++);
302 const char *Equals
= (const char*) memchr(I
, '=', MsgEnd
- I
);
305 const char *End
= (const char*) memchr(Equals
, '\n', MsgEnd
- Equals
);
309 Cnf
.Set(DeQuoteString(string(I
,Equals
-I
)),
310 DeQuoteString(string(Equals
+1,End
-Equals
-1)));
317 // AcqMethod::Run - Run the message engine /*{{{*/
318 // ---------------------------------------------------------------------
319 /* Fetch any messages and execute them. In single mode it returns 1 if
320 there are no more available messages - any other result is a
321 fatal failure code! */
322 int pkgAcqMethod::Run(bool Single
)
326 // Block if the message queue is empty
327 if (Messages
.empty() == true)
330 if (WaitFd(STDIN_FILENO
) == false)
332 if (ReadMessages(STDIN_FILENO
,Messages
) == false)
336 // Single mode exits if the message queue is empty
337 if (Single
== true && Messages
.empty() == true)
340 string Message
= Messages
.front();
341 Messages
.erase(Messages
.begin());
343 // Fetch the message number
345 int Number
= strtol(Message
.c_str(),&End
,10);
346 if (End
== Message
.c_str())
348 cerr
<< "Malformed message!" << endl
;
355 if (Configuration(Message
) == false)
361 FetchItem
*Tmp
= new FetchItem
;
363 Tmp
->Uri
= LookupTag(Message
,"URI");
364 Tmp
->DestFile
= LookupTag(Message
,"FileName");
365 if (RFC1123StrToTime(LookupTag(Message
,"Last-Modified").c_str(),Tmp
->LastModified
) == false)
366 Tmp
->LastModified
= 0;
367 Tmp
->IndexFile
= StringToBool(LookupTag(Message
,"Index-File"),false);
368 Tmp
->FailIgnore
= StringToBool(LookupTag(Message
,"Fail-Ignore"),false);
369 Tmp
->ExpectedHashes
= HashStringList();
370 for (char const * const * t
= HashString::SupportedHashes(); *t
!= NULL
; ++t
)
372 std::string tag
= "Expected-";
374 std::string
const hash
= LookupTag(Message
, tag
.c_str());
375 if (hash
.empty() == false)
376 Tmp
->ExpectedHashes
.push_back(HashString(*t
, hash
));
379 if (Tmp
->ExpectedHashes
.FileSize() > 0)
380 Tmp
->MaximumSize
= Tmp
->ExpectedHashes
.FileSize();
382 Tmp
->MaximumSize
= strtoll(LookupTag(Message
, "Maximum-Size", "0").c_str(), &End
, 10);
385 // Append it to the list
386 FetchItem
**I
= &Queue
;
387 for (; *I
!= 0; I
= &(*I
)->Next
);
392 // Notify that this item is to be fetched.
393 if (URIAcquire(Message
, Tmp
) == false)
405 // AcqMethod::PrintStatus - privately really send a log/status message /*{{{*/
406 void pkgAcqMethod::PrintStatus(char const * const header
, const char* Format
,
409 string CurrentURI
= "<UNKNOWN>";
411 CurrentURI
= Queue
->Uri
;
412 if (UsedMirror
.empty() == true)
413 fprintf(stdout
, "%s\nURI: %s\nMessage: ",
414 header
, CurrentURI
.c_str());
416 fprintf(stdout
, "%s\nURI: %s\nUsedMirror: %s\nMessage: ",
417 header
, CurrentURI
.c_str(), UsedMirror
.c_str());
418 vfprintf(stdout
,Format
,args
);
419 std::cout
<< "\n\n" << std::flush
;
422 // AcqMethod::Log - Send a log message /*{{{*/
423 // ---------------------------------------------------------------------
425 void pkgAcqMethod::Log(const char *Format
,...)
428 va_start(args
,Format
);
429 PrintStatus("101 Log", Format
, args
);
433 // AcqMethod::Status - Send a status message /*{{{*/
434 // ---------------------------------------------------------------------
436 void pkgAcqMethod::Status(const char *Format
,...)
439 va_start(args
,Format
);
440 PrintStatus("102 Status", Format
, args
);
444 // AcqMethod::Redirect - Send a redirect message /*{{{*/
445 // ---------------------------------------------------------------------
446 /* This method sends the redirect message and dequeues the item as
447 * the worker will enqueue again later on to the right queue */
448 void pkgAcqMethod::Redirect(const string
&NewURI
)
450 std::cout
<< "103 Redirect\nURI: " << Queue
->Uri
<< "\n"
451 << "New-URI: " << NewURI
<< "\n"
452 << "\n" << std::flush
;
456 // AcqMethod::FetchResult::FetchResult - Constructor /*{{{*/
457 // ---------------------------------------------------------------------
459 pkgAcqMethod::FetchResult::FetchResult() : LastModified(0),
460 IMSHit(false), Size(0), ResumePoint(0)
464 // AcqMethod::FetchResult::TakeHashes - Load hashes /*{{{*/
465 // ---------------------------------------------------------------------
466 /* This hides the number of hashes we are supporting from the caller.
467 It just deals with the hash class. */
468 void pkgAcqMethod::FetchResult::TakeHashes(class Hashes
&Hash
)
470 Hashes
= Hash
.GetHashStringList();
473 void pkgAcqMethod::Dequeue() { /*{{{*/
474 FetchItem
const * const Tmp
= Queue
;
476 if (Tmp
== QueueBack
)
482 pkgAcqMethod::~pkgAcqMethod() {}