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