]>
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
<< " " << IP
<< "\n";
109 std::cout
<< "400 URI Failure\nURI: <UNKNOWN>\nMessage: " << Err
<< "\n";
111 if(FailReason
.empty() == false)
112 std::cout
<< "FailReason: " << FailReason
<< "\n";
113 if (UsedMirror
.empty() == false)
114 std::cout
<< "UsedMirror: " << UsedMirror
<< "\n";
115 // Set the transient flag
116 if (Transient
== true)
117 std::cout
<< "Transient-Failure: true\n";
119 std::cout
<< "\n" << std::flush
;
122 // AcqMethod::DropPrivsOrDie - Drop privileges or die /*{{{*/
123 // ---------------------------------------------------------------------
125 void pkgAcqMethod::DropPrivsOrDie()
129 exit(112); /* call the european emergency number */
134 // AcqMethod::URIStart - Indicate a download is starting /*{{{*/
135 // ---------------------------------------------------------------------
137 void pkgAcqMethod::URIStart(FetchResult
&Res
)
142 std::cout
<< "200 URI Start\n"
143 << "URI: " << Queue
->Uri
<< "\n";
145 std::cout
<< "Size: " << Res
.Size
<< "\n";
147 if (Res
.LastModified
!= 0)
148 std::cout
<< "Last-Modified: " << TimeRFC1123(Res
.LastModified
) << "\n";
150 if (Res
.ResumePoint
!= 0)
151 std::cout
<< "Resume-Point: " << Res
.ResumePoint
<< "\n";
153 if (UsedMirror
.empty() == false)
154 std::cout
<< "UsedMirror: " << UsedMirror
<< "\n";
156 std::cout
<< "\n" << std::flush
;
159 // AcqMethod::URIDone - A URI is finished /*{{{*/
160 // ---------------------------------------------------------------------
162 static void printHashStringList(HashStringList
const * const list
)
164 for (HashStringList::const_iterator hash
= list
->begin(); hash
!= list
->end(); ++hash
)
166 // very old compatibility name for MD5Sum
167 if (hash
->HashType() == "MD5Sum")
168 std::cout
<< "MD5-Hash: " << hash
->HashValue() << "\n";
169 std::cout
<< hash
->HashType() << "-Hash: " << hash
->HashValue() << "\n";
172 void pkgAcqMethod::URIDone(FetchResult
&Res
, FetchResult
*Alt
)
177 std::cout
<< "201 URI Done\n"
178 << "URI: " << Queue
->Uri
<< "\n";
180 if (Res
.Filename
.empty() == false)
181 std::cout
<< "Filename: " << Res
.Filename
<< "\n";
184 std::cout
<< "Size: " << Res
.Size
<< "\n";
186 if (Res
.LastModified
!= 0)
187 std::cout
<< "Last-Modified: " << TimeRFC1123(Res
.LastModified
) << "\n";
189 printHashStringList(&Res
.Hashes
);
191 if (UsedMirror
.empty() == false)
192 std::cout
<< "UsedMirror: " << UsedMirror
<< "\n";
193 if (Res
.GPGVOutput
.empty() == false)
195 std::cout
<< "GPGVOutput:\n";
196 for (vector
<string
>::const_iterator I
= Res
.GPGVOutput
.begin();
197 I
!= Res
.GPGVOutput
.end(); ++I
)
198 std::cout
<< " " << *I
<< "\n";
201 if (Res
.ResumePoint
!= 0)
202 std::cout
<< "Resume-Point: " << Res
.ResumePoint
<< "\n";
204 if (Res
.IMSHit
== true)
205 std::cout
<< "IMS-Hit: true\n";
209 if (Alt
->Filename
.empty() == false)
210 std::cout
<< "Alt-Filename: " << Alt
->Filename
<< "\n";
213 std::cout
<< "Alt-Size: " << Alt
->Size
<< "\n";
215 if (Alt
->LastModified
!= 0)
216 std::cout
<< "Alt-Last-Modified: " << TimeRFC1123(Alt
->LastModified
) << "\n";
218 printHashStringList(&Alt
->Hashes
);
220 if (Alt
->IMSHit
== true)
221 std::cout
<< "Alt-IMS-Hit: true\n";
224 std::cout
<< "\n" << std::flush
;
228 // AcqMethod::MediaFail - Syncronous request for new media /*{{{*/
229 // ---------------------------------------------------------------------
230 /* This sends a 403 Media Failure message to the APT and waits for it
232 bool pkgAcqMethod::MediaFail(string Required
,string Drive
)
234 fprintf(stdout
, "403 Media Failure\nMedia: %s\nDrive: %s\n",
235 Required
.c_str(),Drive
.c_str());
236 std::cout
<< "\n" << std::flush
;
238 vector
<string
> MyMessages
;
240 /* Here we read messages until we find a 603, each non 603 message is
241 appended to the main message list for later processing */
244 if (WaitFd(STDIN_FILENO
) == false)
247 if (ReadMessages(STDIN_FILENO
,MyMessages
) == false)
250 string Message
= MyMessages
.front();
251 MyMessages
.erase(MyMessages
.begin());
253 // Fetch the message number
255 int Number
= strtol(Message
.c_str(),&End
,10);
256 if (End
== Message
.c_str())
258 cerr
<< "Malformed message!" << endl
;
265 while (MyMessages
.empty() == false)
267 Messages
.push_back(MyMessages
.front());
268 MyMessages
.erase(MyMessages
.begin());
271 return !StringToBool(LookupTag(Message
,"Failed"),false);
274 Messages
.push_back(Message
);
278 // AcqMethod::Configuration - Handle the configuration message /*{{{*/
279 // ---------------------------------------------------------------------
280 /* This parses each configuration entry and puts it into the _config
281 Configuration class. */
282 bool pkgAcqMethod::Configuration(string Message
)
284 ::Configuration
&Cnf
= *_config
;
286 const char *I
= Message
.c_str();
287 const char *MsgEnd
= I
+ Message
.length();
289 unsigned int Length
= strlen("Config-Item");
290 for (; I
+ Length
< MsgEnd
; I
++)
293 if (I
[Length
] != ':' || stringcasecmp(I
,I
+Length
,"Config-Item") != 0)
298 for (; I
< MsgEnd
&& *I
== ' '; I
++);
299 const char *Equals
= (const char*) memchr(I
, '=', MsgEnd
- I
);
302 const char *End
= (const char*) memchr(Equals
, '\n', MsgEnd
- Equals
);
306 Cnf
.Set(DeQuoteString(string(I
,Equals
-I
)),
307 DeQuoteString(string(Equals
+1,End
-Equals
-1)));
314 // AcqMethod::Run - Run the message engine /*{{{*/
315 // ---------------------------------------------------------------------
316 /* Fetch any messages and execute them. In single mode it returns 1 if
317 there are no more available messages - any other result is a
318 fatal failure code! */
319 int pkgAcqMethod::Run(bool Single
)
323 // Block if the message queue is empty
324 if (Messages
.empty() == true)
327 if (WaitFd(STDIN_FILENO
) == false)
329 if (ReadMessages(STDIN_FILENO
,Messages
) == false)
333 // Single mode exits if the message queue is empty
334 if (Single
== true && Messages
.empty() == true)
337 string Message
= Messages
.front();
338 Messages
.erase(Messages
.begin());
340 // Fetch the message number
342 int Number
= strtol(Message
.c_str(),&End
,10);
343 if (End
== Message
.c_str())
345 cerr
<< "Malformed message!" << endl
;
352 if (Configuration(Message
) == false)
358 FetchItem
*Tmp
= new FetchItem
;
360 Tmp
->Uri
= LookupTag(Message
,"URI");
361 Tmp
->DestFile
= LookupTag(Message
,"FileName");
362 if (RFC1123StrToTime(LookupTag(Message
,"Last-Modified").c_str(),Tmp
->LastModified
) == false)
363 Tmp
->LastModified
= 0;
364 Tmp
->IndexFile
= StringToBool(LookupTag(Message
,"Index-File"),false);
365 Tmp
->FailIgnore
= StringToBool(LookupTag(Message
,"Fail-Ignore"),false);
366 Tmp
->ExpectedHashes
= HashStringList();
367 for (char const * const * t
= HashString::SupportedHashes(); *t
!= NULL
; ++t
)
369 std::string tag
= "Expected-";
371 std::string
const hash
= LookupTag(Message
, tag
.c_str());
372 if (hash
.empty() == false)
373 Tmp
->ExpectedHashes
.push_back(HashString(*t
, hash
));
377 // Append it to the list
378 FetchItem
**I
= &Queue
;
379 for (; *I
!= 0; I
= &(*I
)->Next
);
384 // Notify that this item is to be fetched.
385 if (Fetch(Tmp
) == false)
397 // AcqMethod::PrintStatus - privately really send a log/status message /*{{{*/
398 // ---------------------------------------------------------------------
400 void pkgAcqMethod::PrintStatus(char const * const header
, const char* Format
,
403 string CurrentURI
= "<UNKNOWN>";
405 CurrentURI
= Queue
->Uri
;
406 if (UsedMirror
.empty() == true)
407 fprintf(stdout
, "%s\nURI: %s\nMessage: ",
408 header
, CurrentURI
.c_str());
410 fprintf(stdout
, "%s\nURI: %s\nUsedMirror: %s\nMessage: ",
411 header
, CurrentURI
.c_str(), UsedMirror
.c_str());
412 vfprintf(stdout
,Format
,args
);
413 std::cout
<< "\n\n" << std::flush
;
416 // AcqMethod::Log - Send a log message /*{{{*/
417 // ---------------------------------------------------------------------
419 void pkgAcqMethod::Log(const char *Format
,...)
422 va_start(args
,Format
);
423 PrintStatus("101 Log", Format
, args
);
427 // AcqMethod::Status - Send a status message /*{{{*/
428 // ---------------------------------------------------------------------
430 void pkgAcqMethod::Status(const char *Format
,...)
433 va_start(args
,Format
);
434 PrintStatus("102 Status", Format
, args
);
438 // AcqMethod::Redirect - Send a redirect message /*{{{*/
439 // ---------------------------------------------------------------------
440 /* This method sends the redirect message and dequeues the item as
441 * the worker will enqueue again later on to the right queue */
442 void pkgAcqMethod::Redirect(const string
&NewURI
)
444 std::cout
<< "103 Redirect\nURI: " << Queue
->Uri
<< "\n"
445 << "New-URI: " << NewURI
<< "\n"
446 << "\n" << std::flush
;
450 // AcqMethod::FetchResult::FetchResult - Constructor /*{{{*/
451 // ---------------------------------------------------------------------
453 pkgAcqMethod::FetchResult::FetchResult() : LastModified(0),
454 IMSHit(false), Size(0), ResumePoint(0)
458 // AcqMethod::FetchResult::TakeHashes - Load hashes /*{{{*/
459 // ---------------------------------------------------------------------
460 /* This hides the number of hashes we are supporting from the caller.
461 It just deals with the hash class. */
462 void pkgAcqMethod::FetchResult::TakeHashes(class Hashes
&Hash
)
464 Hashes
= Hash
.GetHashStringList();
467 void pkgAcqMethod::Dequeue() { /*{{{*/
468 FetchItem
const * const Tmp
= Queue
;
470 if (Tmp
== QueueBack
)