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