]> git.saurik.com Git - apt.git/blame - apt-pkg/acquire-method.cc
first proof-of-concept for a fix for #731738
[apt.git] / apt-pkg / acquire-method.cc
CommitLineData
93bf083d
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
b3d44315 3// $Id: acquire-method.cc,v 1.27.2.1 2003/12/24 23:09:17 mdz Exp $
93bf083d
AL
4/* ######################################################################
5
6 Acquire Method
7
8384ebdf 8 This is a skeleton class that implements most of the functionality
b2e465d6 9 of a method and some useful functions to make method implementation
8384ebdf
AL
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
13 downloading files..
14
93bf083d
AL
15 ##################################################################### */
16 /*}}}*/
17// Include Files /*{{{*/
ea542140
DK
18#include <config.h>
19
93bf083d
AL
20#include <apt-pkg/acquire-method.h>
21#include <apt-pkg/error.h>
22#include <apt-pkg/configuration.h>
cdcc6d34 23#include <apt-pkg/strutl.h>
93bf083d 24#include <apt-pkg/fileutl.h>
a7c835af 25#include <apt-pkg/hashes.h>
b4fc9b6f
AL
26
27#include <iostream>
93bf083d 28#include <stdio.h>
b3d44315 29#include <sys/signal.h>
93bf083d
AL
30 /*}}}*/
31
b4fc9b6f
AL
32using namespace std;
33
93bf083d
AL
34// AcqMethod::pkgAcqMethod - Constructor /*{{{*/
35// ---------------------------------------------------------------------
36/* This constructs the initialization text */
37pkgAcqMethod::pkgAcqMethod(const char *Ver,unsigned long Flags)
38{
c8848ae2
DK
39 std::cout << "100 Capabilities\n"
40 << "Version: " << Ver << "\n";
93bf083d
AL
41
42 if ((Flags & SingleInstance) == SingleInstance)
c8848ae2
DK
43 std::cout << "Single-Instance: true\n";
44
93bf083d 45 if ((Flags & Pipeline) == Pipeline)
c8848ae2
DK
46 std::cout << "Pipeline: true\n";
47
93bf083d 48 if ((Flags & SendConfig) == SendConfig)
c8848ae2 49 std::cout << "Send-Config: true\n";
e331f6ed
AL
50
51 if ((Flags & LocalOnly) == LocalOnly)
c8848ae2 52 std::cout <<"Local-Only: true\n";
8e5fc8f5
AL
53
54 if ((Flags & NeedsCleanup) == NeedsCleanup)
c8848ae2 55 std::cout << "Needs-Cleanup: true\n";
459681d3
AL
56
57 if ((Flags & Removable) == Removable)
c8848ae2 58 std::cout << "Removable: true\n";
93bf083d 59
c8848ae2 60 std::cout << "\n" << std::flush;
be4401bf
AL
61
62 SetNonBlock(STDIN_FILENO,true);
5cb5d8dc 63
92e889c8 64 Queue = 0;
5cb5d8dc 65 QueueBack = 0;
93bf083d
AL
66}
67 /*}}}*/
68// AcqMethod::Fail - A fetch has failed /*{{{*/
69// ---------------------------------------------------------------------
70/* */
a72ace20 71void pkgAcqMethod::Fail(bool Transient)
93bf083d
AL
72{
73 string Err = "Undetermined Error";
74 if (_error->empty() == false)
75 _error->PopMessage(Err);
76 _error->Discard();
a72ace20 77 Fail(Err,Transient);
93bf083d
AL
78}
79 /*}}}*/
80// AcqMethod::Fail - A fetch has failed /*{{{*/
81// ---------------------------------------------------------------------
82/* */
a72ace20 83void pkgAcqMethod::Fail(string Err,bool Transient)
6d5dd02a
AL
84{
85 // Strip out junk from the error messages
f7f0d6c7 86 for (string::iterator I = Err.begin(); I != Err.end(); ++I)
6d5dd02a
AL
87 {
88 if (*I == '\r')
89 *I = ' ';
90 if (*I == '\n')
91 *I = ' ';
92 }
c8848ae2 93
be4401bf
AL
94 if (Queue != 0)
95 {
c8848ae2
DK
96 std::cout << "400 URI Failure\nURI: " << Queue->Uri << "\n"
97 << "Message: " << Err << " " << IP << "\n";
e1284a59 98 Dequeue();
be4401bf
AL
99 }
100 else
c8848ae2
DK
101 std::cout << "400 URI Failure\nURI: <UNKNOWN>\nMessage: " << Err << "\n";
102
36280399 103 if(FailReason.empty() == false)
c8848ae2 104 std::cout << "FailReason: " << FailReason << "\n";
36280399 105 if (UsedMirror.empty() == false)
c8848ae2
DK
106 std::cout << "UsedMirror: " << UsedMirror << "\n";
107 // Set the transient flag
a72ace20 108 if (Transient == true)
c8848ae2
DK
109 std::cout << "Transient-Failure: true\n";
110
111 std::cout << "\n" << std::flush;
93bf083d
AL
112}
113 /*}}}*/
114// AcqMethod::URIStart - Indicate a download is starting /*{{{*/
115// ---------------------------------------------------------------------
116/* */
be4401bf 117void pkgAcqMethod::URIStart(FetchResult &Res)
93bf083d 118{
be4401bf
AL
119 if (Queue == 0)
120 abort();
c8848ae2
DK
121
122 std::cout << "200 URI Start\n"
123 << "URI: " << Queue->Uri << "\n";
93bf083d 124 if (Res.Size != 0)
c8848ae2
DK
125 std::cout << "Size: " << Res.Size << "\n";
126
93bf083d 127 if (Res.LastModified != 0)
c8848ae2
DK
128 std::cout << "Last-Modified: " << TimeRFC1123(Res.LastModified) << "\n";
129
be4401bf 130 if (Res.ResumePoint != 0)
c8848ae2
DK
131 std::cout << "Resume-Point: " << Res.ResumePoint << "\n";
132
196fd136 133 if (UsedMirror.empty() == false)
c8848ae2
DK
134 std::cout << "UsedMirror: " << UsedMirror << "\n";
135
136 std::cout << "\n" << std::flush;
93bf083d
AL
137}
138 /*}}}*/
139// AcqMethod::URIDone - A URI is finished /*{{{*/
140// ---------------------------------------------------------------------
141/* */
142void pkgAcqMethod::URIDone(FetchResult &Res, FetchResult *Alt)
143{
be4401bf
AL
144 if (Queue == 0)
145 abort();
c8848ae2
DK
146
147 std::cout << "201 URI Done\n"
148 << "URI: " << Queue->Uri << "\n";
93bf083d
AL
149
150 if (Res.Filename.empty() == false)
c8848ae2
DK
151 std::cout << "Filename: " << Res.Filename << "\n";
152
93bf083d 153 if (Res.Size != 0)
c8848ae2
DK
154 std::cout << "Size: " << Res.Size << "\n";
155
93bf083d 156 if (Res.LastModified != 0)
c8848ae2 157 std::cout << "Last-Modified: " << TimeRFC1123(Res.LastModified) << "\n";
93bf083d
AL
158
159 if (Res.MD5Sum.empty() == false)
c8848ae2
DK
160 std::cout << "MD5-Hash: " << Res.MD5Sum << "\n"
161 << "MD5Sum-Hash: " << Res.MD5Sum << "\n";
a7c835af 162 if (Res.SHA1Sum.empty() == false)
c8848ae2 163 std::cout << "SHA1-Hash: " << Res.SHA1Sum << "\n";
5d0d7fae 164 if (Res.SHA256Sum.empty() == false)
c8848ae2 165 std::cout << "SHA256-Hash: " << Res.SHA256Sum << "\n";
d9b9e9e2 166 if (Res.SHA512Sum.empty() == false)
12cd178d 167 std::cout << "SHA512-Hash: " << Res.SHA512Sum << "\n";
36280399 168 if (UsedMirror.empty() == false)
c8848ae2
DK
169 std::cout << "UsedMirror: " << UsedMirror << "\n";
170 if (Res.GPGVOutput.empty() == false)
171 {
172 std::cout << "GPGVOutput:\n";
173 for (vector<string>::const_iterator I = Res.GPGVOutput.begin();
174 I != Res.GPGVOutput.end(); ++I)
175 std::cout << " " << *I << "\n";
176 }
93bf083d 177
b98f2859 178 if (Res.ResumePoint != 0)
c8848ae2 179 std::cout << "Resume-Point: " << Res.ResumePoint << "\n";
b98f2859 180
93bf083d 181 if (Res.IMSHit == true)
c8848ae2
DK
182 std::cout << "IMS-Hit: true\n";
183
93bf083d
AL
184 if (Alt != 0)
185 {
186 if (Alt->Filename.empty() == false)
c8848ae2
DK
187 std::cout << "Alt-Filename: " << Alt->Filename << "\n";
188
93bf083d 189 if (Alt->Size != 0)
c8848ae2
DK
190 std::cout << "Alt-Size: " << Alt->Size << "\n";
191
93bf083d 192 if (Alt->LastModified != 0)
c8848ae2
DK
193 std::cout << "Alt-Last-Modified: " << TimeRFC1123(Alt->LastModified) << "\n";
194
93bf083d 195 if (Alt->MD5Sum.empty() == false)
c8848ae2 196 std::cout << "Alt-MD5-Hash: " << Alt->MD5Sum << "\n";
a7c835af 197 if (Alt->SHA1Sum.empty() == false)
c8848ae2 198 std::cout << "Alt-SHA1-Hash: " << Alt->SHA1Sum << "\n";
5d0d7fae 199 if (Alt->SHA256Sum.empty() == false)
c8848ae2 200 std::cout << "Alt-SHA256-Hash: " << Alt->SHA256Sum << "\n";
d9b9e9e2 201 if (Alt->SHA512Sum.empty() == false)
12cd178d 202 std::cout << "Alt-SHA512-Hash: " << Alt->SHA512Sum << "\n";
d9b9e9e2 203
93bf083d 204 if (Alt->IMSHit == true)
c8848ae2 205 std::cout << "Alt-IMS-Hit: true\n";
93bf083d 206 }
c8848ae2
DK
207
208 std::cout << "\n" << std::flush;
e1284a59 209 Dequeue();
93bf083d
AL
210}
211 /*}}}*/
f46e7681
AL
212// AcqMethod::MediaFail - Syncronous request for new media /*{{{*/
213// ---------------------------------------------------------------------
214/* This sends a 403 Media Failure message to the APT and waits for it
215 to be ackd */
018f1533 216bool pkgAcqMethod::MediaFail(string Required,string Drive)
f46e7681 217{
c8848ae2 218 fprintf(stdout, "403 Media Failure\nMedia: %s\nDrive: %s\n",
f46e7681 219 Required.c_str(),Drive.c_str());
c8848ae2 220 std::cout << "\n" << std::flush;
f46e7681 221
f46e7681
AL
222 vector<string> MyMessages;
223
224 /* Here we read messages until we find a 603, each non 603 message is
225 appended to the main message list for later processing */
226 while (1)
227 {
228 if (WaitFd(STDIN_FILENO) == false)
76d97c26 229 return false;
f46e7681
AL
230
231 if (ReadMessages(STDIN_FILENO,MyMessages) == false)
76d97c26
AL
232 return false;
233
f46e7681
AL
234 string Message = MyMessages.front();
235 MyMessages.erase(MyMessages.begin());
236
237 // Fetch the message number
238 char *End;
239 int Number = strtol(Message.c_str(),&End,10);
240 if (End == Message.c_str())
241 {
242 cerr << "Malformed message!" << endl;
243 exit(100);
244 }
245
246 // Change ack
247 if (Number == 603)
248 {
76d97c26 249 while (MyMessages.empty() == false)
f46e7681
AL
250 {
251 Messages.push_back(MyMessages.front());
252 MyMessages.erase(MyMessages.begin());
253 }
542ec555 254
2a749770 255 return !StringToBool(LookupTag(Message,"Failed"),false);
f46e7681
AL
256 }
257
258 Messages.push_back(Message);
259 }
260}
261 /*}}}*/
93bf083d
AL
262// AcqMethod::Configuration - Handle the configuration message /*{{{*/
263// ---------------------------------------------------------------------
264/* This parses each configuration entry and puts it into the _config
265 Configuration class. */
266bool pkgAcqMethod::Configuration(string Message)
267{
268 ::Configuration &Cnf = *_config;
269
b4fc9b6f
AL
270 const char *I = Message.c_str();
271 const char *MsgEnd = I + Message.length();
93bf083d
AL
272
273 unsigned int Length = strlen("Config-Item");
b4fc9b6f 274 for (; I + Length < MsgEnd; I++)
93bf083d
AL
275 {
276 // Not a config item
277 if (I[Length] != ':' || stringcasecmp(I,I+Length,"Config-Item") != 0)
278 continue;
279
280 I += Length + 1;
281
b4fc9b6f 282 for (; I < MsgEnd && *I == ' '; I++);
404528bd
DK
283 const char *Equals = (const char*) memchr(I, '=', MsgEnd - I);
284 if (Equals == NULL)
93bf083d 285 return false;
404528bd
DK
286 const char *End = (const char*) memchr(Equals, '\n', MsgEnd - Equals);
287 if (End == NULL)
288 End = MsgEnd;
93bf083d 289
6d5dd02a
AL
290 Cnf.Set(DeQuoteString(string(I,Equals-I)),
291 DeQuoteString(string(Equals+1,End-Equals-1)));
93bf083d
AL
292 I = End;
293 }
294
295 return true;
296}
297 /*}}}*/
298// AcqMethod::Run - Run the message engine /*{{{*/
299// ---------------------------------------------------------------------
8384ebdf
AL
300/* Fetch any messages and execute them. In single mode it returns 1 if
301 there are no more available messages - any other result is a
302 fatal failure code! */
be4401bf 303int pkgAcqMethod::Run(bool Single)
93bf083d 304{
93bf083d
AL
305 while (1)
306 {
be4401bf 307 // Block if the message queue is empty
93bf083d 308 if (Messages.empty() == true)
be4401bf
AL
309 {
310 if (Single == false)
311 if (WaitFd(STDIN_FILENO) == false)
8e5fc8f5 312 break;
92e889c8 313 if (ReadMessages(STDIN_FILENO,Messages) == false)
8e5fc8f5 314 break;
92e889c8
AL
315 }
316
be4401bf
AL
317 // Single mode exits if the message queue is empty
318 if (Single == true && Messages.empty() == true)
8384ebdf 319 return -1;
be4401bf 320
93bf083d
AL
321 string Message = Messages.front();
322 Messages.erase(Messages.begin());
323
324 // Fetch the message number
325 char *End;
326 int Number = strtol(Message.c_str(),&End,10);
327 if (End == Message.c_str())
328 {
329 cerr << "Malformed message!" << endl;
330 return 100;
331 }
332
333 switch (Number)
8e5fc8f5 334 {
93bf083d
AL
335 case 601:
336 if (Configuration(Message) == false)
337 return 100;
338 break;
339
340 case 600:
be4401bf
AL
341 {
342 FetchItem *Tmp = new FetchItem;
343
344 Tmp->Uri = LookupTag(Message,"URI");
345 Tmp->DestFile = LookupTag(Message,"FileName");
96cc64a5 346 if (RFC1123StrToTime(LookupTag(Message,"Last-Modified").c_str(),Tmp->LastModified) == false)
b98f2859 347 Tmp->LastModified = 0;
a72ace20 348 Tmp->IndexFile = StringToBool(LookupTag(Message,"Index-File"),false);
963b16dc 349 Tmp->FailIgnore = StringToBool(LookupTag(Message,"Fail-Ignore"),false);
be4401bf
AL
350 Tmp->Next = 0;
351
352 // Append it to the list
353 FetchItem **I = &Queue;
92e889c8 354 for (; *I != 0; I = &(*I)->Next);
be4401bf 355 *I = Tmp;
5cb5d8dc
AL
356 if (QueueBack == 0)
357 QueueBack = Tmp;
358
bfd22fc0 359 // Notify that this item is to be fetched.
be4401bf 360 if (Fetch(Tmp) == false)
93bf083d 361 Fail();
bfd22fc0 362
93bf083d
AL
363 break;
364 }
365 }
366 }
367
8e5fc8f5 368 Exit();
93bf083d
AL
369 return 0;
370}
371 /*}}}*/
f1bdfe81 372// AcqMethod::PrintStatus - privately really send a log/status message /*{{{*/
be4401bf
AL
373// ---------------------------------------------------------------------
374/* */
f1bdfe81
DK
375void pkgAcqMethod::PrintStatus(char const * const header, const char* Format,
376 va_list &args) const
be4401bf
AL
377{
378 string CurrentURI = "<UNKNOWN>";
379 if (Queue != 0)
380 CurrentURI = Queue->Uri;
f1bdfe81
DK
381 if (UsedMirror.empty() == true)
382 fprintf(stdout, "%s\nURI: %s\nMessage: ",
383 header, CurrentURI.c_str());
384 else
385 fprintf(stdout, "%s\nURI: %s\nUsedMirror: %s\nMessage: ",
386 header, CurrentURI.c_str(), UsedMirror.c_str());
387 vfprintf(stdout,Format,args);
388 std::cout << "\n\n" << std::flush;
389}
390 /*}}}*/
391// AcqMethod::Log - Send a log message /*{{{*/
392// ---------------------------------------------------------------------
393/* */
394void pkgAcqMethod::Log(const char *Format,...)
395{
be4401bf
AL
396 va_list args;
397 va_start(args,Format);
f1bdfe81 398 PrintStatus("101 Log", Format, args);
c8848ae2 399 va_end(args);
be4401bf
AL
400}
401 /*}}}*/
402// AcqMethod::Status - Send a status message /*{{{*/
403// ---------------------------------------------------------------------
404/* */
405void pkgAcqMethod::Status(const char *Format,...)
406{
be4401bf
AL
407 va_list args;
408 va_start(args,Format);
f1bdfe81 409 PrintStatus("102 Status", Format, args);
c8848ae2 410 va_end(args);
be4401bf
AL
411}
412 /*}}}*/
ebb461fd
MV
413// AcqMethod::Redirect - Send a redirect message /*{{{*/
414// ---------------------------------------------------------------------
5674f6b3
RG
415/* This method sends the redirect message and dequeues the item as
416 * the worker will enqueue again later on to the right queue */
ebb461fd
MV
417void pkgAcqMethod::Redirect(const string &NewURI)
418{
b40b7c38
DK
419 std::cout << "103 Redirect\nURI: " << Queue->Uri << "\n"
420 << "New-URI: " << NewURI << "\n"
c8848ae2 421 << "\n" << std::flush;
5674f6b3 422 Dequeue();
ebb461fd
MV
423}
424 /*}}}*/
93bf083d
AL
425// AcqMethod::FetchResult::FetchResult - Constructor /*{{{*/
426// ---------------------------------------------------------------------
427/* */
93274b8d
AL
428pkgAcqMethod::FetchResult::FetchResult() : LastModified(0),
429 IMSHit(false), Size(0), ResumePoint(0)
93bf083d
AL
430{
431}
432 /*}}}*/
a7c835af
AL
433// AcqMethod::FetchResult::TakeHashes - Load hashes /*{{{*/
434// ---------------------------------------------------------------------
435/* This hides the number of hashes we are supporting from the caller.
436 It just deals with the hash class. */
437void pkgAcqMethod::FetchResult::TakeHashes(Hashes &Hash)
438{
439 MD5Sum = Hash.MD5.Result();
440 SHA1Sum = Hash.SHA1.Result();
5d0d7fae 441 SHA256Sum = Hash.SHA256.Result();
d9b9e9e2 442 SHA512Sum = Hash.SHA512.Result();
a7c835af
AL
443}
444 /*}}}*/
e1284a59
DK
445void pkgAcqMethod::Dequeue() { /*{{{*/
446 FetchItem const * const Tmp = Queue;
447 Queue = Queue->Next;
448 if (Tmp == QueueBack)
449 QueueBack = Queue;
450 delete Tmp;
451}
452 /*}}}*/