]>
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 /*{{{*/
18 #include <apt-pkg/acquire-method.h>
19 #include <apt-pkg/error.h>
20 #include <apt-pkg/configuration.h>
21 #include <apt-pkg/strutl.h>
22 #include <apt-pkg/fileutl.h>
23 #include <apt-pkg/hashes.h>
27 #include <sys/signal.h>
32 // AcqMethod::pkgAcqMethod - Constructor /*{{{*/
33 // ---------------------------------------------------------------------
34 /* This constructs the initialization text */
35 pkgAcqMethod::pkgAcqMethod(const char *Ver
,unsigned long Flags
)
37 std::cout
<< "100 Capabilities\n"
38 << "Version: " << Ver
<< "\n";
40 if ((Flags
& SingleInstance
) == SingleInstance
)
41 std::cout
<< "Single-Instance: true\n";
43 if ((Flags
& Pipeline
) == Pipeline
)
44 std::cout
<< "Pipeline: true\n";
46 if ((Flags
& SendConfig
) == SendConfig
)
47 std::cout
<< "Send-Config: true\n";
49 if ((Flags
& LocalOnly
) == LocalOnly
)
50 std::cout
<<"Local-Only: true\n";
52 if ((Flags
& NeedsCleanup
) == NeedsCleanup
)
53 std::cout
<< "Needs-Cleanup: true\n";
55 if ((Flags
& Removable
) == Removable
)
56 std::cout
<< "Removable: true\n";
58 std::cout
<< "\n" << std::flush
;
60 SetNonBlock(STDIN_FILENO
,true);
66 // AcqMethod::Fail - A fetch has failed /*{{{*/
67 // ---------------------------------------------------------------------
69 void pkgAcqMethod::Fail(bool Transient
)
71 string Err
= "Undetermined Error";
72 if (_error
->empty() == false)
73 _error
->PopMessage(Err
);
78 // AcqMethod::Fail - A fetch has failed /*{{{*/
79 // ---------------------------------------------------------------------
81 void pkgAcqMethod::Fail(string Err
,bool Transient
)
83 // Strip out junk from the error messages
84 for (string::iterator I
= Err
.begin(); I
!= Err
.end(); ++I
)
94 std::cout
<< "400 URI Failure\nURI: " << Queue
->Uri
<< "\n"
95 << "Message: " << Err
<< " " << IP
<< "\n";
97 FetchItem
*Tmp
= Queue
;
100 if (Tmp
== QueueBack
)
104 std::cout
<< "400 URI Failure\nURI: <UNKNOWN>\nMessage: " << Err
<< "\n";
106 if(FailReason
.empty() == false)
107 std::cout
<< "FailReason: " << FailReason
<< "\n";
108 if (UsedMirror
.empty() == false)
109 std::cout
<< "UsedMirror: " << UsedMirror
<< "\n";
110 // Set the transient flag
111 if (Transient
== true)
112 std::cout
<< "Transient-Failure: true\n";
114 std::cout
<< "\n" << std::flush
;
117 // AcqMethod::URIStart - Indicate a download is starting /*{{{*/
118 // ---------------------------------------------------------------------
120 void pkgAcqMethod::URIStart(FetchResult
&Res
)
125 std::cout
<< "200 URI Start\n"
126 << "URI: " << Queue
->Uri
<< "\n";
128 std::cout
<< "Size: " << Res
.Size
<< "\n";
130 if (Res
.LastModified
!= 0)
131 std::cout
<< "Last-Modified: " << TimeRFC1123(Res
.LastModified
) << "\n";
133 if (Res
.ResumePoint
!= 0)
134 std::cout
<< "Resume-Point: " << Res
.ResumePoint
<< "\n";
136 if (UsedMirror
.empty() == false)
137 std::cout
<< "UsedMirror: " << UsedMirror
<< "\n";
139 std::cout
<< "\n" << std::flush
;
142 // AcqMethod::URIDone - A URI is finished /*{{{*/
143 // ---------------------------------------------------------------------
145 void pkgAcqMethod::URIDone(FetchResult
&Res
, FetchResult
*Alt
)
150 std::cout
<< "201 URI Done\n"
151 << "URI: " << Queue
->Uri
<< "\n";
153 if (Res
.Filename
.empty() == false)
154 std::cout
<< "Filename: " << Res
.Filename
<< "\n";
157 std::cout
<< "Size: " << Res
.Size
<< "\n";
159 if (Res
.LastModified
!= 0)
160 std::cout
<< "Last-Modified: " << TimeRFC1123(Res
.LastModified
) << "\n";
162 if (Res
.MD5Sum
.empty() == false)
163 std::cout
<< "MD5-Hash: " << Res
.MD5Sum
<< "\n"
164 << "MD5Sum-Hash: " << Res
.MD5Sum
<< "\n";
165 if (Res
.SHA1Sum
.empty() == false)
166 std::cout
<< "SHA1-Hash: " << Res
.SHA1Sum
<< "\n";
167 if (Res
.SHA256Sum
.empty() == false)
168 std::cout
<< "SHA256-Hash: " << Res
.SHA256Sum
<< "\n";
169 if (UsedMirror
.empty() == false)
170 std::cout
<< "UsedMirror: " << UsedMirror
<< "\n";
171 if (Res
.GPGVOutput
.empty() == false)
173 std::cout
<< "GPGVOutput:\n";
174 for (vector
<string
>::const_iterator I
= Res
.GPGVOutput
.begin();
175 I
!= Res
.GPGVOutput
.end(); ++I
)
176 std::cout
<< " " << *I
<< "\n";
179 if (Res
.ResumePoint
!= 0)
180 std::cout
<< "Resume-Point: " << Res
.ResumePoint
<< "\n";
182 if (Res
.IMSHit
== true)
183 std::cout
<< "IMS-Hit: true\n";
187 if (Alt
->Filename
.empty() == false)
188 std::cout
<< "Alt-Filename: " << Alt
->Filename
<< "\n";
191 std::cout
<< "Alt-Size: " << Alt
->Size
<< "\n";
193 if (Alt
->LastModified
!= 0)
194 std::cout
<< "Alt-Last-Modified: " << TimeRFC1123(Alt
->LastModified
) << "\n";
196 if (Alt
->MD5Sum
.empty() == false)
197 std::cout
<< "Alt-MD5-Hash: " << Alt
->MD5Sum
<< "\n";
198 if (Alt
->SHA1Sum
.empty() == false)
199 std::cout
<< "Alt-SHA1-Hash: " << Alt
->SHA1Sum
<< "\n";
200 if (Alt
->SHA256Sum
.empty() == false)
201 std::cout
<< "Alt-SHA256-Hash: " << Alt
->SHA256Sum
<< "\n";
203 if (Alt
->IMSHit
== true)
204 std::cout
<< "Alt-IMS-Hit: true\n";
207 std::cout
<< "\n" << std::flush
;
210 FetchItem
*Tmp
= Queue
;
213 if (Tmp
== QueueBack
)
217 // AcqMethod::MediaFail - Syncronous request for new media /*{{{*/
218 // ---------------------------------------------------------------------
219 /* This sends a 403 Media Failure message to the APT and waits for it
221 bool pkgAcqMethod::MediaFail(string Required
,string Drive
)
223 fprintf(stdout
, "403 Media Failure\nMedia: %s\nDrive: %s\n",
224 Required
.c_str(),Drive
.c_str());
225 std::cout
<< "\n" << std::flush
;
227 vector
<string
> MyMessages
;
229 /* Here we read messages until we find a 603, each non 603 message is
230 appended to the main message list for later processing */
233 if (WaitFd(STDIN_FILENO
) == false)
236 if (ReadMessages(STDIN_FILENO
,MyMessages
) == false)
239 string Message
= MyMessages
.front();
240 MyMessages
.erase(MyMessages
.begin());
242 // Fetch the message number
244 int Number
= strtol(Message
.c_str(),&End
,10);
245 if (End
== Message
.c_str())
247 cerr
<< "Malformed message!" << endl
;
254 while (MyMessages
.empty() == false)
256 Messages
.push_back(MyMessages
.front());
257 MyMessages
.erase(MyMessages
.begin());
260 return !StringToBool(LookupTag(Message
,"Failed"),false);
263 Messages
.push_back(Message
);
267 // AcqMethod::Configuration - Handle the configuration message /*{{{*/
268 // ---------------------------------------------------------------------
269 /* This parses each configuration entry and puts it into the _config
270 Configuration class. */
271 bool pkgAcqMethod::Configuration(string Message
)
273 ::Configuration
&Cnf
= *_config
;
275 const char *I
= Message
.c_str();
276 const char *MsgEnd
= I
+ Message
.length();
278 unsigned int Length
= strlen("Config-Item");
279 for (; I
+ Length
< MsgEnd
; I
++)
282 if (I
[Length
] != ':' || stringcasecmp(I
,I
+Length
,"Config-Item") != 0)
287 for (; I
< MsgEnd
&& *I
== ' '; I
++);
288 const char *Equals
= (const char*) memchr(I
, '=', MsgEnd
- I
);
291 const char *End
= (const char*) memchr(Equals
, '\n', MsgEnd
- Equals
);
295 Cnf
.Set(DeQuoteString(string(I
,Equals
-I
)),
296 DeQuoteString(string(Equals
+1,End
-Equals
-1)));
303 // AcqMethod::Run - Run the message engine /*{{{*/
304 // ---------------------------------------------------------------------
305 /* Fetch any messages and execute them. In single mode it returns 1 if
306 there are no more available messages - any other result is a
307 fatal failure code! */
308 int pkgAcqMethod::Run(bool Single
)
312 // Block if the message queue is empty
313 if (Messages
.empty() == true)
316 if (WaitFd(STDIN_FILENO
) == false)
318 if (ReadMessages(STDIN_FILENO
,Messages
) == false)
322 // Single mode exits if the message queue is empty
323 if (Single
== true && Messages
.empty() == true)
326 string Message
= Messages
.front();
327 Messages
.erase(Messages
.begin());
329 // Fetch the message number
331 int Number
= strtol(Message
.c_str(),&End
,10);
332 if (End
== Message
.c_str())
334 cerr
<< "Malformed message!" << endl
;
341 if (Configuration(Message
) == false)
347 FetchItem
*Tmp
= new FetchItem
;
349 Tmp
->Uri
= LookupTag(Message
,"URI");
350 Tmp
->DestFile
= LookupTag(Message
,"FileName");
351 if (RFC1123StrToTime(LookupTag(Message
,"Last-Modified").c_str(),Tmp
->LastModified
) == false)
352 Tmp
->LastModified
= 0;
353 Tmp
->IndexFile
= StringToBool(LookupTag(Message
,"Index-File"),false);
354 Tmp
->FailIgnore
= StringToBool(LookupTag(Message
,"Fail-Ignore"),false);
357 // Append it to the list
358 FetchItem
**I
= &Queue
;
359 for (; *I
!= 0; I
= &(*I
)->Next
);
364 // Notify that this item is to be fetched.
365 if (Fetch(Tmp
) == false)
377 // AcqMethod::PrintStatus - privately really send a log/status message /*{{{*/
378 // ---------------------------------------------------------------------
380 void pkgAcqMethod::PrintStatus(char const * const header
, const char* Format
,
383 string CurrentURI
= "<UNKNOWN>";
385 CurrentURI
= Queue
->Uri
;
386 if (UsedMirror
.empty() == true)
387 fprintf(stdout
, "%s\nURI: %s\nMessage: ",
388 header
, CurrentURI
.c_str());
390 fprintf(stdout
, "%s\nURI: %s\nUsedMirror: %s\nMessage: ",
391 header
, CurrentURI
.c_str(), UsedMirror
.c_str());
392 vfprintf(stdout
,Format
,args
);
393 std::cout
<< "\n\n" << std::flush
;
396 // AcqMethod::Log - Send a log message /*{{{*/
397 // ---------------------------------------------------------------------
399 void pkgAcqMethod::Log(const char *Format
,...)
402 va_start(args
,Format
);
403 PrintStatus("101 Log", Format
, args
);
407 // AcqMethod::Status - Send a status message /*{{{*/
408 // ---------------------------------------------------------------------
410 void pkgAcqMethod::Status(const char *Format
,...)
413 va_start(args
,Format
);
414 PrintStatus("102 Status", Format
, args
);
418 // AcqMethod::Redirect - Send a redirect message /*{{{*/
419 // ---------------------------------------------------------------------
420 /* This method sends the redirect message and also manipulates the queue
421 to keep the pipeline synchronized. */
422 void pkgAcqMethod::Redirect(const string
&NewURI
)
424 std::cout
<< "103 Redirect\nURI: " << Queue
->Uri
<< "\n"
425 << "New-URI: " << NewURI
<< "\n"
426 << "\n" << std::flush
;
428 // Change the URI for the request.
431 /* To keep the pipeline synchronized, move the current request to
432 the end of the queue, past the end of the current pipeline. */
434 for (I
= Queue
; I
->Next
!= 0; I
= I
->Next
) ;
442 // AcqMethod::FetchResult::FetchResult - Constructor /*{{{*/
443 // ---------------------------------------------------------------------
445 pkgAcqMethod::FetchResult::FetchResult() : LastModified(0),
446 IMSHit(false), Size(0), ResumePoint(0)
450 // AcqMethod::FetchResult::TakeHashes - Load hashes /*{{{*/
451 // ---------------------------------------------------------------------
452 /* This hides the number of hashes we are supporting from the caller.
453 It just deals with the hash class. */
454 void pkgAcqMethod::FetchResult::TakeHashes(Hashes
&Hash
)
456 MD5Sum
= Hash
.MD5
.Result();
457 SHA1Sum
= Hash
.SHA1
.Result();
458 SHA256Sum
= Hash
.SHA256
.Result();