]>
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>
29 #include <sys/signal.h>
34 // AcqMethod::pkgAcqMethod - Constructor /*{{{*/
35 // ---------------------------------------------------------------------
36 /* This constructs the initialization text */
37 pkgAcqMethod::pkgAcqMethod(const char *Ver
,unsigned long Flags
)
39 std::cout
<< "100 Capabilities\n"
40 << "Version: " << Ver
<< "\n";
42 if ((Flags
& SingleInstance
) == SingleInstance
)
43 std::cout
<< "Single-Instance: true\n";
45 if ((Flags
& Pipeline
) == Pipeline
)
46 std::cout
<< "Pipeline: true\n";
48 if ((Flags
& SendConfig
) == SendConfig
)
49 std::cout
<< "Send-Config: true\n";
51 if ((Flags
& LocalOnly
) == LocalOnly
)
52 std::cout
<<"Local-Only: true\n";
54 if ((Flags
& NeedsCleanup
) == NeedsCleanup
)
55 std::cout
<< "Needs-Cleanup: true\n";
57 if ((Flags
& Removable
) == Removable
)
58 std::cout
<< "Removable: true\n";
60 std::cout
<< "\n" << std::flush
;
62 SetNonBlock(STDIN_FILENO
,true);
68 // AcqMethod::Fail - A fetch has failed /*{{{*/
69 // ---------------------------------------------------------------------
71 void pkgAcqMethod::Fail(bool Transient
)
73 string Err
= "Undetermined Error";
74 if (_error
->empty() == false)
75 _error
->PopMessage(Err
);
80 // AcqMethod::Fail - A fetch has failed /*{{{*/
81 // ---------------------------------------------------------------------
83 void pkgAcqMethod::Fail(string Err
,bool Transient
)
85 // Strip out junk from the error messages
86 for (string::iterator I
= Err
.begin(); I
!= Err
.end(); ++I
)
96 std::cout
<< "400 URI Failure\nURI: " << Queue
->Uri
<< "\n"
97 << "Message: " << Err
<< " " << IP
<< "\n";
99 FetchItem
*Tmp
= Queue
;
102 if (Tmp
== QueueBack
)
106 std::cout
<< "400 URI Failure\nURI: <UNKNOWN>\nMessage: " << Err
<< "\n";
108 if(FailReason
.empty() == false)
109 std::cout
<< "FailReason: " << FailReason
<< "\n";
110 if (UsedMirror
.empty() == false)
111 std::cout
<< "UsedMirror: " << UsedMirror
<< "\n";
112 // Set the transient flag
113 if (Transient
== true)
114 std::cout
<< "Transient-Failure: true\n";
116 std::cout
<< "\n" << std::flush
;
119 // AcqMethod::URIStart - Indicate a download is starting /*{{{*/
120 // ---------------------------------------------------------------------
122 void pkgAcqMethod::URIStart(FetchResult
&Res
)
127 std::cout
<< "200 URI Start\n"
128 << "URI: " << Queue
->Uri
<< "\n";
130 std::cout
<< "Size: " << Res
.Size
<< "\n";
132 if (Res
.LastModified
!= 0)
133 std::cout
<< "Last-Modified: " << TimeRFC1123(Res
.LastModified
) << "\n";
135 if (Res
.ResumePoint
!= 0)
136 std::cout
<< "Resume-Point: " << Res
.ResumePoint
<< "\n";
138 if (UsedMirror
.empty() == false)
139 std::cout
<< "UsedMirror: " << UsedMirror
<< "\n";
141 std::cout
<< "\n" << std::flush
;
144 // AcqMethod::URIDone - A URI is finished /*{{{*/
145 // ---------------------------------------------------------------------
147 void pkgAcqMethod::URIDone(FetchResult
&Res
, FetchResult
*Alt
)
152 std::cout
<< "201 URI Done\n"
153 << "URI: " << Queue
->Uri
<< "\n";
155 if (Res
.Filename
.empty() == false)
156 std::cout
<< "Filename: " << Res
.Filename
<< "\n";
159 std::cout
<< "Size: " << Res
.Size
<< "\n";
161 if (Res
.LastModified
!= 0)
162 std::cout
<< "Last-Modified: " << TimeRFC1123(Res
.LastModified
) << "\n";
164 if (Res
.MD5Sum
.empty() == false)
165 std::cout
<< "MD5-Hash: " << Res
.MD5Sum
<< "\n"
166 << "MD5Sum-Hash: " << Res
.MD5Sum
<< "\n";
167 if (Res
.SHA1Sum
.empty() == false)
168 std::cout
<< "SHA1-Hash: " << Res
.SHA1Sum
<< "\n";
169 if (Res
.SHA256Sum
.empty() == false)
170 std::cout
<< "SHA256-Hash: " << Res
.SHA256Sum
<< "\n";
171 if (Res
.SHA512Sum
.empty() == false)
172 std::cout
<< "SHA512-Hash: " << Res
.SHA512Sum
<< "\n";
173 if (UsedMirror
.empty() == false)
174 std::cout
<< "UsedMirror: " << UsedMirror
<< "\n";
175 if (Res
.GPGVOutput
.empty() == false)
177 std::cout
<< "GPGVOutput:\n";
178 for (vector
<string
>::const_iterator I
= Res
.GPGVOutput
.begin();
179 I
!= Res
.GPGVOutput
.end(); ++I
)
180 std::cout
<< " " << *I
<< "\n";
183 if (Res
.ResumePoint
!= 0)
184 std::cout
<< "Resume-Point: " << Res
.ResumePoint
<< "\n";
186 if (Res
.IMSHit
== true)
187 std::cout
<< "IMS-Hit: true\n";
191 if (Alt
->Filename
.empty() == false)
192 std::cout
<< "Alt-Filename: " << Alt
->Filename
<< "\n";
195 std::cout
<< "Alt-Size: " << Alt
->Size
<< "\n";
197 if (Alt
->LastModified
!= 0)
198 std::cout
<< "Alt-Last-Modified: " << TimeRFC1123(Alt
->LastModified
) << "\n";
200 if (Alt
->MD5Sum
.empty() == false)
201 std::cout
<< "Alt-MD5-Hash: " << Alt
->MD5Sum
<< "\n";
202 if (Alt
->SHA1Sum
.empty() == false)
203 std::cout
<< "Alt-SHA1-Hash: " << Alt
->SHA1Sum
<< "\n";
204 if (Alt
->SHA256Sum
.empty() == false)
205 std::cout
<< "Alt-SHA256-Hash: " << Alt
->SHA256Sum
<< "\n";
206 if (Alt
->SHA512Sum
.empty() == false)
207 std::cout
<< "Alt-SHA512-Hash: " << Alt
->SHA512Sum
<< "\n";
209 if (Alt
->IMSHit
== true)
210 std::cout
<< "Alt-IMS-Hit: true\n";
213 std::cout
<< "\n" << std::flush
;
216 FetchItem
*Tmp
= Queue
;
219 if (Tmp
== QueueBack
)
223 // AcqMethod::MediaFail - Syncronous request for new media /*{{{*/
224 // ---------------------------------------------------------------------
225 /* This sends a 403 Media Failure message to the APT and waits for it
227 bool pkgAcqMethod::MediaFail(string Required
,string Drive
)
229 fprintf(stdout
, "403 Media Failure\nMedia: %s\nDrive: %s\n",
230 Required
.c_str(),Drive
.c_str());
231 std::cout
<< "\n" << std::flush
;
233 vector
<string
> MyMessages
;
235 /* Here we read messages until we find a 603, each non 603 message is
236 appended to the main message list for later processing */
239 if (WaitFd(STDIN_FILENO
) == false)
242 if (ReadMessages(STDIN_FILENO
,MyMessages
) == false)
245 string Message
= MyMessages
.front();
246 MyMessages
.erase(MyMessages
.begin());
248 // Fetch the message number
250 int Number
= strtol(Message
.c_str(),&End
,10);
251 if (End
== Message
.c_str())
253 cerr
<< "Malformed message!" << endl
;
260 while (MyMessages
.empty() == false)
262 Messages
.push_back(MyMessages
.front());
263 MyMessages
.erase(MyMessages
.begin());
266 return !StringToBool(LookupTag(Message
,"Failed"),false);
269 Messages
.push_back(Message
);
273 // AcqMethod::Configuration - Handle the configuration message /*{{{*/
274 // ---------------------------------------------------------------------
275 /* This parses each configuration entry and puts it into the _config
276 Configuration class. */
277 bool pkgAcqMethod::Configuration(string Message
)
279 ::Configuration
&Cnf
= *_config
;
281 const char *I
= Message
.c_str();
282 const char *MsgEnd
= I
+ Message
.length();
284 unsigned int Length
= strlen("Config-Item");
285 for (; I
+ Length
< MsgEnd
; I
++)
288 if (I
[Length
] != ':' || stringcasecmp(I
,I
+Length
,"Config-Item") != 0)
293 for (; I
< MsgEnd
&& *I
== ' '; I
++);
294 const char *Equals
= (const char*) memchr(I
, '=', MsgEnd
- I
);
297 const char *End
= (const char*) memchr(Equals
, '\n', MsgEnd
- Equals
);
301 Cnf
.Set(DeQuoteString(string(I
,Equals
-I
)),
302 DeQuoteString(string(Equals
+1,End
-Equals
-1)));
309 // AcqMethod::Run - Run the message engine /*{{{*/
310 // ---------------------------------------------------------------------
311 /* Fetch any messages and execute them. In single mode it returns 1 if
312 there are no more available messages - any other result is a
313 fatal failure code! */
314 int pkgAcqMethod::Run(bool Single
)
318 // Block if the message queue is empty
319 if (Messages
.empty() == true)
322 if (WaitFd(STDIN_FILENO
) == false)
324 if (ReadMessages(STDIN_FILENO
,Messages
) == false)
328 // Single mode exits if the message queue is empty
329 if (Single
== true && Messages
.empty() == true)
332 string Message
= Messages
.front();
333 Messages
.erase(Messages
.begin());
335 // Fetch the message number
337 int Number
= strtol(Message
.c_str(),&End
,10);
338 if (End
== Message
.c_str())
340 cerr
<< "Malformed message!" << endl
;
347 if (Configuration(Message
) == false)
353 FetchItem
*Tmp
= new FetchItem
;
355 Tmp
->Uri
= LookupTag(Message
,"URI");
356 Tmp
->DestFile
= LookupTag(Message
,"FileName");
357 if (RFC1123StrToTime(LookupTag(Message
,"Last-Modified").c_str(),Tmp
->LastModified
) == false)
358 Tmp
->LastModified
= 0;
359 Tmp
->IndexFile
= StringToBool(LookupTag(Message
,"Index-File"),false);
360 Tmp
->FailIgnore
= StringToBool(LookupTag(Message
,"Fail-Ignore"),false);
363 // Append it to the list
364 FetchItem
**I
= &Queue
;
365 for (; *I
!= 0; I
= &(*I
)->Next
);
370 // Notify that this item is to be fetched.
371 if (Fetch(Tmp
) == false)
383 // AcqMethod::PrintStatus - privately really send a log/status message /*{{{*/
384 // ---------------------------------------------------------------------
386 void pkgAcqMethod::PrintStatus(char const * const header
, const char* Format
,
389 string CurrentURI
= "<UNKNOWN>";
391 CurrentURI
= Queue
->Uri
;
392 if (UsedMirror
.empty() == true)
393 fprintf(stdout
, "%s\nURI: %s\nMessage: ",
394 header
, CurrentURI
.c_str());
396 fprintf(stdout
, "%s\nURI: %s\nUsedMirror: %s\nMessage: ",
397 header
, CurrentURI
.c_str(), UsedMirror
.c_str());
398 vfprintf(stdout
,Format
,args
);
399 std::cout
<< "\n\n" << std::flush
;
402 // AcqMethod::Log - Send a log message /*{{{*/
403 // ---------------------------------------------------------------------
405 void pkgAcqMethod::Log(const char *Format
,...)
408 va_start(args
,Format
);
409 PrintStatus("101 Log", Format
, args
);
413 // AcqMethod::Status - Send a status message /*{{{*/
414 // ---------------------------------------------------------------------
416 void pkgAcqMethod::Status(const char *Format
,...)
419 va_start(args
,Format
);
420 PrintStatus("102 Status", Format
, args
);
424 // AcqMethod::Redirect - Send a redirect message /*{{{*/
425 // ---------------------------------------------------------------------
426 /* This method sends the redirect message and also manipulates the queue
427 to keep the pipeline synchronized. */
428 void pkgAcqMethod::Redirect(const string
&NewURI
)
430 std::cout
<< "103 Redirect\nURI: " << Queue
->Uri
<< "\n"
431 << "New-URI: " << NewURI
<< "\n"
432 << "\n" << std::flush
;
434 // Change the URI for the request.
437 /* To keep the pipeline synchronized, move the current request to
438 the end of the queue, past the end of the current pipeline. */
440 for (I
= Queue
; I
->Next
!= 0; I
= I
->Next
) ;
448 // AcqMethod::FetchResult::FetchResult - Constructor /*{{{*/
449 // ---------------------------------------------------------------------
451 pkgAcqMethod::FetchResult::FetchResult() : LastModified(0),
452 IMSHit(false), Size(0), ResumePoint(0)
456 // AcqMethod::FetchResult::TakeHashes - Load hashes /*{{{*/
457 // ---------------------------------------------------------------------
458 /* This hides the number of hashes we are supporting from the caller.
459 It just deals with the hash class. */
460 void pkgAcqMethod::FetchResult::TakeHashes(Hashes
&Hash
)
462 MD5Sum
= Hash
.MD5
.Result();
463 SHA1Sum
= Hash
.SHA1
.Result();
464 SHA256Sum
= Hash
.SHA256
.Result();
465 SHA512Sum
= Hash
.SHA512
.Result();