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