tell download methods the expected hashes
[ntk/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
AL
120}
121 /*}}}*/
122// AcqMethod::URIStart - Indicate a download is starting /*{{{*/
123// ---------------------------------------------------------------------
124/* */
be4401bf 125void pkgAcqMethod::URIStart(FetchResult &Res)
93bf083d 126{
be4401bf
AL
127 if (Queue == 0)
128 abort();
c8848ae2
DK
129
130 std::cout << "200 URI Start\n"
131 << "URI: " << Queue->Uri << "\n";
93bf083d 132 if (Res.Size != 0)
c8848ae2
DK
133 std::cout << "Size: " << Res.Size << "\n";
134
93bf083d 135 if (Res.LastModified != 0)
c8848ae2
DK
136 std::cout << "Last-Modified: " << TimeRFC1123(Res.LastModified) << "\n";
137
be4401bf 138 if (Res.ResumePoint != 0)
c8848ae2
DK
139 std::cout << "Resume-Point: " << Res.ResumePoint << "\n";
140
196fd136 141 if (UsedMirror.empty() == false)
c8848ae2
DK
142 std::cout << "UsedMirror: " << UsedMirror << "\n";
143
144 std::cout << "\n" << std::flush;
93bf083d
AL
145}
146 /*}}}*/
147// AcqMethod::URIDone - A URI is finished /*{{{*/
148// ---------------------------------------------------------------------
149/* */
b3501edb
DK
150static void printHashStringList(HashStringList const * const list)
151{
152 for (HashStringList::const_iterator hash = list->begin(); hash != list->end(); ++hash)
153 {
154 // very old compatibility name for MD5Sum
155 if (hash->HashType() == "MD5Sum")
156 std::cout << "MD5-Hash: " << hash->HashValue() << "\n";
157 std::cout << hash->HashType() << "-Hash: " << hash->HashValue() << "\n";
158 }
159}
93bf083d
AL
160void pkgAcqMethod::URIDone(FetchResult &Res, FetchResult *Alt)
161{
be4401bf
AL
162 if (Queue == 0)
163 abort();
c8848ae2
DK
164
165 std::cout << "201 URI Done\n"
166 << "URI: " << Queue->Uri << "\n";
93bf083d
AL
167
168 if (Res.Filename.empty() == false)
c8848ae2
DK
169 std::cout << "Filename: " << Res.Filename << "\n";
170
93bf083d 171 if (Res.Size != 0)
c8848ae2
DK
172 std::cout << "Size: " << Res.Size << "\n";
173
93bf083d 174 if (Res.LastModified != 0)
c8848ae2 175 std::cout << "Last-Modified: " << TimeRFC1123(Res.LastModified) << "\n";
93bf083d 176
b3501edb
DK
177 printHashStringList(&Res.Hashes);
178
36280399 179 if (UsedMirror.empty() == false)
c8848ae2
DK
180 std::cout << "UsedMirror: " << UsedMirror << "\n";
181 if (Res.GPGVOutput.empty() == false)
182 {
183 std::cout << "GPGVOutput:\n";
184 for (vector<string>::const_iterator I = Res.GPGVOutput.begin();
185 I != Res.GPGVOutput.end(); ++I)
186 std::cout << " " << *I << "\n";
187 }
93bf083d 188
b98f2859 189 if (Res.ResumePoint != 0)
c8848ae2 190 std::cout << "Resume-Point: " << Res.ResumePoint << "\n";
b98f2859 191
93bf083d 192 if (Res.IMSHit == true)
c8848ae2
DK
193 std::cout << "IMS-Hit: true\n";
194
93bf083d
AL
195 if (Alt != 0)
196 {
197 if (Alt->Filename.empty() == false)
c8848ae2
DK
198 std::cout << "Alt-Filename: " << Alt->Filename << "\n";
199
93bf083d 200 if (Alt->Size != 0)
c8848ae2
DK
201 std::cout << "Alt-Size: " << Alt->Size << "\n";
202
93bf083d 203 if (Alt->LastModified != 0)
c8848ae2
DK
204 std::cout << "Alt-Last-Modified: " << TimeRFC1123(Alt->LastModified) << "\n";
205
b3501edb
DK
206 printHashStringList(&Alt->Hashes);
207
93bf083d 208 if (Alt->IMSHit == true)
c8848ae2 209 std::cout << "Alt-IMS-Hit: true\n";
93bf083d 210 }
c8848ae2
DK
211
212 std::cout << "\n" << std::flush;
e1284a59 213 Dequeue();
93bf083d
AL
214}
215 /*}}}*/
f46e7681
AL
216// AcqMethod::MediaFail - Syncronous request for new media /*{{{*/
217// ---------------------------------------------------------------------
218/* This sends a 403 Media Failure message to the APT and waits for it
219 to be ackd */
018f1533 220bool pkgAcqMethod::MediaFail(string Required,string Drive)
f46e7681 221{
c8848ae2 222 fprintf(stdout, "403 Media Failure\nMedia: %s\nDrive: %s\n",
f46e7681 223 Required.c_str(),Drive.c_str());
c8848ae2 224 std::cout << "\n" << std::flush;
f46e7681 225
f46e7681
AL
226 vector<string> MyMessages;
227
228 /* Here we read messages until we find a 603, each non 603 message is
229 appended to the main message list for later processing */
230 while (1)
231 {
232 if (WaitFd(STDIN_FILENO) == false)
76d97c26 233 return false;
f46e7681
AL
234
235 if (ReadMessages(STDIN_FILENO,MyMessages) == false)
76d97c26
AL
236 return false;
237
f46e7681
AL
238 string Message = MyMessages.front();
239 MyMessages.erase(MyMessages.begin());
240
241 // Fetch the message number
242 char *End;
243 int Number = strtol(Message.c_str(),&End,10);
244 if (End == Message.c_str())
245 {
246 cerr << "Malformed message!" << endl;
247 exit(100);
248 }
249
250 // Change ack
251 if (Number == 603)
252 {
76d97c26 253 while (MyMessages.empty() == false)
f46e7681
AL
254 {
255 Messages.push_back(MyMessages.front());
256 MyMessages.erase(MyMessages.begin());
257 }
542ec555 258
2a749770 259 return !StringToBool(LookupTag(Message,"Failed"),false);
f46e7681
AL
260 }
261
262 Messages.push_back(Message);
263 }
264}
265 /*}}}*/
93bf083d
AL
266// AcqMethod::Configuration - Handle the configuration message /*{{{*/
267// ---------------------------------------------------------------------
268/* This parses each configuration entry and puts it into the _config
269 Configuration class. */
270bool pkgAcqMethod::Configuration(string Message)
271{
272 ::Configuration &Cnf = *_config;
273
b4fc9b6f
AL
274 const char *I = Message.c_str();
275 const char *MsgEnd = I + Message.length();
93bf083d
AL
276
277 unsigned int Length = strlen("Config-Item");
b4fc9b6f 278 for (; I + Length < MsgEnd; I++)
93bf083d
AL
279 {
280 // Not a config item
281 if (I[Length] != ':' || stringcasecmp(I,I+Length,"Config-Item") != 0)
282 continue;
283
284 I += Length + 1;
285
b4fc9b6f 286 for (; I < MsgEnd && *I == ' '; I++);
404528bd
DK
287 const char *Equals = (const char*) memchr(I, '=', MsgEnd - I);
288 if (Equals == NULL)
93bf083d 289 return false;
404528bd
DK
290 const char *End = (const char*) memchr(Equals, '\n', MsgEnd - Equals);
291 if (End == NULL)
292 End = MsgEnd;
93bf083d 293
6d5dd02a
AL
294 Cnf.Set(DeQuoteString(string(I,Equals-I)),
295 DeQuoteString(string(Equals+1,End-Equals-1)));
93bf083d
AL
296 I = End;
297 }
298
299 return true;
300}
301 /*}}}*/
302// AcqMethod::Run - Run the message engine /*{{{*/
303// ---------------------------------------------------------------------
8384ebdf
AL
304/* Fetch any messages and execute them. In single mode it returns 1 if
305 there are no more available messages - any other result is a
306 fatal failure code! */
be4401bf 307int pkgAcqMethod::Run(bool Single)
93bf083d 308{
93bf083d
AL
309 while (1)
310 {
be4401bf 311 // Block if the message queue is empty
93bf083d 312 if (Messages.empty() == true)
be4401bf
AL
313 {
314 if (Single == false)
315 if (WaitFd(STDIN_FILENO) == false)
8e5fc8f5 316 break;
92e889c8 317 if (ReadMessages(STDIN_FILENO,Messages) == false)
8e5fc8f5 318 break;
92e889c8
AL
319 }
320
be4401bf
AL
321 // Single mode exits if the message queue is empty
322 if (Single == true && Messages.empty() == true)
8384ebdf 323 return -1;
be4401bf 324
93bf083d
AL
325 string Message = Messages.front();
326 Messages.erase(Messages.begin());
327
328 // Fetch the message number
329 char *End;
330 int Number = strtol(Message.c_str(),&End,10);
331 if (End == Message.c_str())
332 {
333 cerr << "Malformed message!" << endl;
334 return 100;
335 }
336
337 switch (Number)
8e5fc8f5 338 {
93bf083d
AL
339 case 601:
340 if (Configuration(Message) == false)
341 return 100;
342 break;
343
344 case 600:
be4401bf
AL
345 {
346 FetchItem *Tmp = new FetchItem;
347
348 Tmp->Uri = LookupTag(Message,"URI");
349 Tmp->DestFile = LookupTag(Message,"FileName");
96cc64a5 350 if (RFC1123StrToTime(LookupTag(Message,"Last-Modified").c_str(),Tmp->LastModified) == false)
b98f2859 351 Tmp->LastModified = 0;
a72ace20 352 Tmp->IndexFile = StringToBool(LookupTag(Message,"Index-File"),false);
963b16dc 353 Tmp->FailIgnore = StringToBool(LookupTag(Message,"Fail-Ignore"),false);
d003a557
DK
354 Tmp->ExpectedHashes = HashStringList();
355 for (char const * const * t = HashString::SupportedHashes(); *t != NULL; ++t)
356 {
357 std::string tag = "Expected-";
358 tag.append(*t);
359 std::string const hash = LookupTag(Message, tag.c_str());
360 if (hash.empty() == false)
361 Tmp->ExpectedHashes.push_back(HashString(*t, hash));
362 }
be4401bf
AL
363 Tmp->Next = 0;
364
365 // Append it to the list
366 FetchItem **I = &Queue;
92e889c8 367 for (; *I != 0; I = &(*I)->Next);
be4401bf 368 *I = Tmp;
5cb5d8dc
AL
369 if (QueueBack == 0)
370 QueueBack = Tmp;
371
bfd22fc0 372 // Notify that this item is to be fetched.
be4401bf 373 if (Fetch(Tmp) == false)
93bf083d 374 Fail();
bfd22fc0 375
93bf083d
AL
376 break;
377 }
378 }
379 }
380
8e5fc8f5 381 Exit();
93bf083d
AL
382 return 0;
383}
384 /*}}}*/
f1bdfe81 385// AcqMethod::PrintStatus - privately really send a log/status message /*{{{*/
be4401bf
AL
386// ---------------------------------------------------------------------
387/* */
f1bdfe81
DK
388void pkgAcqMethod::PrintStatus(char const * const header, const char* Format,
389 va_list &args) const
be4401bf
AL
390{
391 string CurrentURI = "<UNKNOWN>";
392 if (Queue != 0)
393 CurrentURI = Queue->Uri;
f1bdfe81
DK
394 if (UsedMirror.empty() == true)
395 fprintf(stdout, "%s\nURI: %s\nMessage: ",
396 header, CurrentURI.c_str());
397 else
398 fprintf(stdout, "%s\nURI: %s\nUsedMirror: %s\nMessage: ",
399 header, CurrentURI.c_str(), UsedMirror.c_str());
400 vfprintf(stdout,Format,args);
401 std::cout << "\n\n" << std::flush;
402}
403 /*}}}*/
404// AcqMethod::Log - Send a log message /*{{{*/
405// ---------------------------------------------------------------------
406/* */
407void pkgAcqMethod::Log(const char *Format,...)
408{
be4401bf
AL
409 va_list args;
410 va_start(args,Format);
f1bdfe81 411 PrintStatus("101 Log", Format, args);
c8848ae2 412 va_end(args);
be4401bf
AL
413}
414 /*}}}*/
415// AcqMethod::Status - Send a status message /*{{{*/
416// ---------------------------------------------------------------------
417/* */
418void pkgAcqMethod::Status(const char *Format,...)
419{
be4401bf
AL
420 va_list args;
421 va_start(args,Format);
f1bdfe81 422 PrintStatus("102 Status", Format, args);
c8848ae2 423 va_end(args);
be4401bf
AL
424}
425 /*}}}*/
ebb461fd
MV
426// AcqMethod::Redirect - Send a redirect message /*{{{*/
427// ---------------------------------------------------------------------
5674f6b3
RG
428/* This method sends the redirect message and dequeues the item as
429 * the worker will enqueue again later on to the right queue */
ebb461fd
MV
430void pkgAcqMethod::Redirect(const string &NewURI)
431{
b40b7c38
DK
432 std::cout << "103 Redirect\nURI: " << Queue->Uri << "\n"
433 << "New-URI: " << NewURI << "\n"
c8848ae2 434 << "\n" << std::flush;
5674f6b3 435 Dequeue();
ebb461fd
MV
436}
437 /*}}}*/
93bf083d
AL
438// AcqMethod::FetchResult::FetchResult - Constructor /*{{{*/
439// ---------------------------------------------------------------------
440/* */
93274b8d
AL
441pkgAcqMethod::FetchResult::FetchResult() : LastModified(0),
442 IMSHit(false), Size(0), ResumePoint(0)
93bf083d
AL
443{
444}
445 /*}}}*/
a7c835af
AL
446// AcqMethod::FetchResult::TakeHashes - Load hashes /*{{{*/
447// ---------------------------------------------------------------------
448/* This hides the number of hashes we are supporting from the caller.
449 It just deals with the hash class. */
b3501edb 450void pkgAcqMethod::FetchResult::TakeHashes(class Hashes &Hash)
a7c835af 451{
b3501edb 452 Hashes = Hash.GetHashStringList();
a7c835af
AL
453}
454 /*}}}*/
e1284a59
DK
455void pkgAcqMethod::Dequeue() { /*{{{*/
456 FetchItem const * const Tmp = Queue;
457 Queue = Queue->Next;
458 if (Tmp == QueueBack)
459 QueueBack = Queue;
460 delete Tmp;
461}
462 /*}}}*/