]> git.saurik.com Git - apt.git/blame - apt-pkg/acquire-method.cc
releasing package apt version 1.1~exp3
[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 }
be4401bf
AL
375 Tmp->Next = 0;
376
377 // Append it to the list
378 FetchItem **I = &Queue;
92e889c8 379 for (; *I != 0; I = &(*I)->Next);
be4401bf 380 *I = Tmp;
5cb5d8dc
AL
381 if (QueueBack == 0)
382 QueueBack = Tmp;
383
bfd22fc0 384 // Notify that this item is to be fetched.
be4401bf 385 if (Fetch(Tmp) == false)
93bf083d 386 Fail();
bfd22fc0 387
93bf083d
AL
388 break;
389 }
390 }
391 }
392
8e5fc8f5 393 Exit();
93bf083d
AL
394 return 0;
395}
396 /*}}}*/
f1bdfe81 397// AcqMethod::PrintStatus - privately really send a log/status message /*{{{*/
be4401bf
AL
398// ---------------------------------------------------------------------
399/* */
f1bdfe81
DK
400void pkgAcqMethod::PrintStatus(char const * const header, const char* Format,
401 va_list &args) const
be4401bf
AL
402{
403 string CurrentURI = "<UNKNOWN>";
404 if (Queue != 0)
405 CurrentURI = Queue->Uri;
f1bdfe81
DK
406 if (UsedMirror.empty() == true)
407 fprintf(stdout, "%s\nURI: %s\nMessage: ",
408 header, CurrentURI.c_str());
409 else
410 fprintf(stdout, "%s\nURI: %s\nUsedMirror: %s\nMessage: ",
411 header, CurrentURI.c_str(), UsedMirror.c_str());
412 vfprintf(stdout,Format,args);
413 std::cout << "\n\n" << std::flush;
414}
415 /*}}}*/
416// AcqMethod::Log - Send a log message /*{{{*/
417// ---------------------------------------------------------------------
418/* */
419void pkgAcqMethod::Log(const char *Format,...)
420{
be4401bf
AL
421 va_list args;
422 va_start(args,Format);
f1bdfe81 423 PrintStatus("101 Log", Format, args);
c8848ae2 424 va_end(args);
be4401bf
AL
425}
426 /*}}}*/
427// AcqMethod::Status - Send a status message /*{{{*/
428// ---------------------------------------------------------------------
429/* */
430void pkgAcqMethod::Status(const char *Format,...)
431{
be4401bf
AL
432 va_list args;
433 va_start(args,Format);
f1bdfe81 434 PrintStatus("102 Status", Format, args);
c8848ae2 435 va_end(args);
be4401bf
AL
436}
437 /*}}}*/
ebb461fd
MV
438// AcqMethod::Redirect - Send a redirect message /*{{{*/
439// ---------------------------------------------------------------------
5674f6b3
RG
440/* This method sends the redirect message and dequeues the item as
441 * the worker will enqueue again later on to the right queue */
ebb461fd
MV
442void pkgAcqMethod::Redirect(const string &NewURI)
443{
b40b7c38
DK
444 std::cout << "103 Redirect\nURI: " << Queue->Uri << "\n"
445 << "New-URI: " << NewURI << "\n"
c8848ae2 446 << "\n" << std::flush;
5674f6b3 447 Dequeue();
ebb461fd
MV
448}
449 /*}}}*/
93bf083d
AL
450// AcqMethod::FetchResult::FetchResult - Constructor /*{{{*/
451// ---------------------------------------------------------------------
452/* */
93274b8d
AL
453pkgAcqMethod::FetchResult::FetchResult() : LastModified(0),
454 IMSHit(false), Size(0), ResumePoint(0)
93bf083d
AL
455{
456}
457 /*}}}*/
a7c835af
AL
458// AcqMethod::FetchResult::TakeHashes - Load hashes /*{{{*/
459// ---------------------------------------------------------------------
460/* This hides the number of hashes we are supporting from the caller.
461 It just deals with the hash class. */
b3501edb 462void pkgAcqMethod::FetchResult::TakeHashes(class Hashes &Hash)
a7c835af 463{
b3501edb 464 Hashes = Hash.GetHashStringList();
a7c835af
AL
465}
466 /*}}}*/
e1284a59
DK
467void pkgAcqMethod::Dequeue() { /*{{{*/
468 FetchItem const * const Tmp = Queue;
469 Queue = Queue->Next;
470 if (Tmp == QueueBack)
471 QueueBack = Queue;
472 delete Tmp;
473}
474 /*}}}*/