]>
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
));
376 Tmp
->ExpectedSize
= strtoll(LookupTag(Message
, "Expected-Size", "0").c_str(), &End
, 10);
379 // Append it to the list
380 FetchItem
**I
= &Queue
;
381 for (; *I
!= 0; I
= &(*I
)->Next
);
386 // Notify that this item is to be fetched.
387 if (Fetch(Tmp
) == false)
399 // AcqMethod::PrintStatus - privately really send a log/status message /*{{{*/
400 // ---------------------------------------------------------------------
402 void pkgAcqMethod::PrintStatus(char const * const header
, const char* Format
,
405 string CurrentURI
= "<UNKNOWN>";
407 CurrentURI
= Queue
->Uri
;
408 if (UsedMirror
.empty() == true)
409 fprintf(stdout
, "%s\nURI: %s\nMessage: ",
410 header
, CurrentURI
.c_str());
412 fprintf(stdout
, "%s\nURI: %s\nUsedMirror: %s\nMessage: ",
413 header
, CurrentURI
.c_str(), UsedMirror
.c_str());
414 vfprintf(stdout
,Format
,args
);
415 std::cout
<< "\n\n" << std::flush
;
418 // AcqMethod::Log - Send a log message /*{{{*/
419 // ---------------------------------------------------------------------
421 void pkgAcqMethod::Log(const char *Format
,...)
424 va_start(args
,Format
);
425 PrintStatus("101 Log", Format
, args
);
429 // AcqMethod::Status - Send a status message /*{{{*/
430 // ---------------------------------------------------------------------
432 void pkgAcqMethod::Status(const char *Format
,...)
435 va_start(args
,Format
);
436 PrintStatus("102 Status", Format
, args
);
440 // AcqMethod::Redirect - Send a redirect message /*{{{*/
441 // ---------------------------------------------------------------------
442 /* This method sends the redirect message and dequeues the item as
443 * the worker will enqueue again later on to the right queue */
444 void pkgAcqMethod::Redirect(const string
&NewURI
)
446 std::cout
<< "103 Redirect\nURI: " << Queue
->Uri
<< "\n"
447 << "New-URI: " << NewURI
<< "\n"
448 << "\n" << std::flush
;
452 // AcqMethod::FetchResult::FetchResult - Constructor /*{{{*/
453 // ---------------------------------------------------------------------
455 pkgAcqMethod::FetchResult::FetchResult() : LastModified(0),
456 IMSHit(false), Size(0), ResumePoint(0)
460 // AcqMethod::FetchResult::TakeHashes - Load hashes /*{{{*/
461 // ---------------------------------------------------------------------
462 /* This hides the number of hashes we are supporting from the caller.
463 It just deals with the hash class. */
464 void pkgAcqMethod::FetchResult::TakeHashes(class Hashes
&Hash
)
466 Hashes
= Hash
.GetHashStringList();
469 void pkgAcqMethod::Dequeue() { /*{{{*/
470 FetchItem
const * const Tmp
= Queue
;
472 if (Tmp
== QueueBack
)