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