]> git.saurik.com Git - apt.git/blame - apt-pkg/acquire-worker.cc
allow methods to be disabled and redirected via config
[apt.git] / apt-pkg / acquire-worker.cc
CommitLineData
0118833a
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
24a0d63a 3// $Id: acquire-worker.cc,v 1.34 2001/05/22 04:42:54 jgg Exp $
0118833a
AL
4/* ######################################################################
5
6 Acquire Worker
7
3b5421b4
AL
8 The worker process can startup either as a Configuration prober
9 or as a queue runner. As a configuration prober it only reads the
10 configuration message and
11
0118833a
AL
12 ##################################################################### */
13 /*}}}*/
14// Include Files /*{{{*/
ea542140
DK
15#include <config.h>
16
453b82a3 17#include <apt-pkg/acquire.h>
0118833a 18#include <apt-pkg/acquire-worker.h>
0a8a80e5 19#include <apt-pkg/acquire-item.h>
3b5421b4
AL
20#include <apt-pkg/configuration.h>
21#include <apt-pkg/error.h>
22#include <apt-pkg/fileutl.h>
cdcc6d34 23#include <apt-pkg/strutl.h>
453b82a3 24#include <apt-pkg/hashes.h>
3b5421b4 25
9f301e0f 26#include <algorithm>
453b82a3
DK
27#include <string>
28#include <vector>
24a0d63a 29#include <iostream>
ea542140 30
8267fe24 31#include <sys/stat.h>
453b82a3 32#include <stdlib.h>
3b5421b4
AL
33#include <unistd.h>
34#include <signal.h>
542ec555 35#include <stdio.h>
b0db36b1 36#include <errno.h>
ac7f8f79 37#include <sstream>
ea542140
DK
38
39#include <apti18n.h>
3b5421b4
AL
40 /*}}}*/
41
24a0d63a
AL
42using namespace std;
43
3b5421b4 44// Worker::Worker - Constructor for Queue startup /*{{{*/
2651f1c0
DK
45pkgAcquire::Worker::Worker(Queue *Q, MethodConfig *Cnf, pkgAcquireStatus *log) :
46 d(NULL), OwnerQ(Q), Log(log), Config(Cnf), Access(Cnf->Access),
47 CurrentItem(nullptr), CurrentSize(0), TotalSize(0)
3b5421b4 48{
448c38bd 49 Construct();
3b5421b4
AL
50}
51 /*}}}*/
52// Worker::Worker - Constructor for method config startup /*{{{*/
2651f1c0 53pkgAcquire::Worker::Worker(MethodConfig *Cnf) : Worker(nullptr, Cnf, nullptr)
3b5421b4 54{
3b5421b4
AL
55}
56 /*}}}*/
57// Worker::Construct - Constructor helper /*{{{*/
58// ---------------------------------------------------------------------
59/* */
60void pkgAcquire::Worker::Construct()
61{
0a8a80e5
AL
62 NextQueue = 0;
63 NextAcquire = 0;
3b5421b4
AL
64 Process = -1;
65 InFd = -1;
66 OutFd = -1;
0a8a80e5
AL
67 OutReady = false;
68 InReady = false;
3b5421b4
AL
69 Debug = _config->FindB("Debug::pkgAcquire::Worker",false);
70}
71 /*}}}*/
72// Worker::~Worker - Destructor /*{{{*/
73// ---------------------------------------------------------------------
74/* */
75pkgAcquire::Worker::~Worker()
76{
77 close(InFd);
78 close(OutFd);
79
80 if (Process > 0)
0a8a80e5 81 {
8e5fc8f5
AL
82 /* Closing of stdin is the signal to exit and die when the process
83 indicates it needs cleanup */
84 if (Config->NeedsCleanup == false)
85 kill(Process,SIGINT);
ddc1d8d0 86 ExecWait(Process,Access.c_str(),true);
0a8a80e5 87 }
3b5421b4
AL
88}
89 /*}}}*/
90// Worker::Start - Start the worker process /*{{{*/
91// ---------------------------------------------------------------------
92/* This forks the method and inits the communication channel */
93bool pkgAcquire::Worker::Start()
94{
95 // Get the method path
c9c91069
DK
96 constexpr char const * const methodsDir = "Dir::Bin::Methods";
97 std::string const confItem = std::string(methodsDir) + "::" + Access;
98 std::string Method;
99 if (_config->Exists(confItem))
100 Method = _config->FindFile(confItem.c_str());
101 else
102 Method = _config->FindDir(methodsDir) + Access;
3b5421b4 103 if (FileExists(Method) == false)
9082a1fc 104 {
c9c91069
DK
105 if (flNotDir(Method) == "false")
106 {
107 _error->Error(_("The method '%s' is explicitly disabled via configuration."), Access.c_str());
108 if (Access == "http" || Access == "https")
109 _error->Notice(_("If you meant to use Tor remember to use %s instead of %s."), ("tor+" + Access).c_str(), Access.c_str());
110 return false;
111 }
9082a1fc 112 _error->Error(_("The method driver %s could not be found."),Method.c_str());
d0ef5714
DK
113 std::string const A(Access.cbegin(), std::find(Access.cbegin(), Access.cend(), '+'));
114 std::string pkg;
115 strprintf(pkg, "apt-transport-%s", A.c_str());
116 _error->Notice(_("Is the package %s installed?"), pkg.c_str());
9082a1fc
DK
117 return false;
118 }
c9c91069 119 std::string const Calling = _config->FindDir(methodsDir) + Access;
3b5421b4
AL
120
121 if (Debug == true)
c9c91069
DK
122 {
123 std::clog << "Starting method '" << Calling << "'";
124 if (Calling != Method)
125 std::clog << " ( via " << Method << " )";
126 std::clog << endl;
127 }
3b5421b4
AL
128
129 // Create the pipes
130 int Pipes[4] = {-1,-1,-1,-1};
131 if (pipe(Pipes) != 0 || pipe(Pipes+2) != 0)
132 {
133 _error->Errno("pipe","Failed to create IPC pipe to subprocess");
134 for (int I = 0; I != 4; I++)
135 close(Pipes[I]);
136 return false;
137 }
8b89e57f 138 for (int I = 0; I != 4; I++)
4490f2de 139 SetCloseExec(Pipes[I],true);
448c38bd 140
3b5421b4 141 // Fork off the process
54676e1a 142 Process = ExecFork();
3b5421b4
AL
143 if (Process == 0)
144 {
145 // Setup the FDs
146 dup2(Pipes[1],STDOUT_FILENO);
147 dup2(Pipes[2],STDIN_FILENO);
3b5421b4 148 SetCloseExec(STDOUT_FILENO,false);
448c38bd 149 SetCloseExec(STDIN_FILENO,false);
3b5421b4 150 SetCloseExec(STDERR_FILENO,false);
448c38bd 151
c9c91069
DK
152 const char * const Args[] = { Calling.c_str(), nullptr };
153 execv(Method.c_str() ,const_cast<char **>(Args));
154 std::cerr << "Failed to exec method " << Calling << " ( via " << Method << ")" << endl;
0dbb95d8 155 _exit(100);
3b5421b4
AL
156 }
157
158 // Fix up our FDs
159 InFd = Pipes[0];
160 OutFd = Pipes[3];
161 SetNonBlock(Pipes[0],true);
162 SetNonBlock(Pipes[3],true);
163 close(Pipes[1]);
164 close(Pipes[2]);
0a8a80e5
AL
165 OutReady = false;
166 InReady = true;
448c38bd 167
3b5421b4
AL
168 // Read the configuration data
169 if (WaitFd(InFd) == false ||
170 ReadMessages() == false)
b2e465d6 171 return _error->Error(_("Method %s did not start correctly"),Method.c_str());
3b5421b4
AL
172
173 RunMessages();
8b89e57f
AL
174 if (OwnerQ != 0)
175 SendConfiguration();
448c38bd 176
3b5421b4
AL
177 return true;
178}
179 /*}}}*/
180// Worker::ReadMessages - Read all pending messages into the list /*{{{*/
181// ---------------------------------------------------------------------
0a8a80e5 182/* */
3b5421b4
AL
183bool pkgAcquire::Worker::ReadMessages()
184{
0a8a80e5
AL
185 if (::ReadMessages(InFd,MessageQueue) == false)
186 return MethodFailure();
3b5421b4
AL
187 return true;
188}
189 /*}}}*/
3b5421b4
AL
190// Worker::RunMessage - Empty the message queue /*{{{*/
191// ---------------------------------------------------------------------
192/* This takes the messages from the message queue and runs them through
193 the parsers in order. */
38f8704e
DK
194enum class APT_HIDDEN MessageType {
195 CAPABILITIES = 100,
196 LOG = 101,
197 STATUS = 102,
198 REDIRECT = 103,
199 WARNING = 104,
200 URI_START = 200,
201 URI_DONE = 201,
202 URI_FAILURE = 400,
203 GENERAL_FAILURE = 401,
204 MEDIA_CHANGE = 403
205};
206static bool isDoomedItem(pkgAcquire::Item const * const Itm)
207{
208 auto const TransItm = dynamic_cast<pkgAcqTransactionItem const * const>(Itm);
209 if (TransItm == nullptr)
210 return false;
211 return TransItm->TransactionManager->State != pkgAcqTransactionItem::TransactionStarted;
212}
3b5421b4
AL
213bool pkgAcquire::Worker::RunMessages()
214{
215 while (MessageQueue.empty() == false)
216 {
217 string Message = MessageQueue.front();
218 MessageQueue.erase(MessageQueue.begin());
0a8a80e5
AL
219
220 if (Debug == true)
221 clog << " <- " << Access << ':' << QuoteString(Message,"\n") << endl;
448c38bd 222
3b5421b4
AL
223 // Fetch the message number
224 char *End;
38f8704e 225 MessageType const Number = static_cast<MessageType>(strtoul(Message.c_str(),&End,10));
3b5421b4
AL
226 if (End == Message.c_str())
227 return _error->Error("Invalid message from method %s: %s",Access.c_str(),Message.c_str());
228
c88edf1d 229 string URI = LookupTag(Message,"URI");
a4b8112b 230 pkgAcquire::Queue::QItem *Itm = NULL;
c88edf1d
AL
231 if (URI.empty() == false)
232 Itm = OwnerQ->FindItem(URI,this);
196fd136 233
a4b8112b 234 if (Itm != NULL)
196fd136 235 {
a4b8112b
DK
236 // update used mirror
237 string UsedMirror = LookupTag(Message,"UsedMirror", "");
238 if (UsedMirror.empty() == false)
239 {
240 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
241 (*O)->UsedMirror = UsedMirror;
242
243 if (Itm->Description.find(" ") != string::npos)
244 Itm->Description.replace(0, Itm->Description.find(" "), UsedMirror);
245 }
196fd136 246 }
448c38bd 247
3b5421b4
AL
248 // Determine the message number and dispatch
249 switch (Number)
250 {
38f8704e 251 case MessageType::CAPABILITIES:
3b5421b4
AL
252 if (Capabilities(Message) == false)
253 return _error->Error("Unable to process Capabilities message from %s",Access.c_str());
254 break;
448c38bd 255
38f8704e 256 case MessageType::LOG:
0a8a80e5
AL
257 if (Debug == true)
258 clog << " <- (log) " << LookupTag(Message,"Message") << endl;
259 break;
448c38bd 260
38f8704e 261 case MessageType::STATUS:
0a8a80e5
AL
262 Status = LookupTag(Message,"Message");
263 break;
448c38bd 264
38f8704e 265 case MessageType::REDIRECT:
15d7e515 266 {
38f8704e 267 if (Itm == nullptr)
15d7e515
MV
268 {
269 _error->Error("Method gave invalid 103 Redirect message");
270 break;
271 }
448c38bd 272
a4b8112b 273 std::string const NewURI = LookupTag(Message,"New-URI",URI.c_str());
15d7e515 274 Itm->URI = NewURI;
5674f6b3
RG
275
276 ItemDone();
277
5674f6b3 278 // Change the status so that it can be dequeued
ae732225
DK
279 for (auto const &O: Itm->Owners)
280 O->Status = pkgAcquire::Item::StatIdle;
5674f6b3
RG
281 // Mark the item as done (taking care of all queues)
282 // and then put it in the main queue again
08ea7806 283 std::vector<Item*> const ItmOwners = Itm->Owners;
5674f6b3 284 OwnerQ->ItemDone(Itm);
38f8704e
DK
285 Itm = nullptr;
286 for (auto const &Owner: ItmOwners)
08ea7806 287 {
a4b8112b 288 pkgAcquire::ItemDesc &desc = Owner->GetItemDesc();
57401c48
DK
289 if (Owner->IsRedirectionLoop(NewURI))
290 {
291 std::string msg = Message;
292 msg.append("\nFailReason: RedirectionLoop");
293 Owner->Failed(msg, Config);
294 if (Log != nullptr)
295 Log->Fail(Owner->GetItemDesc());
296 continue;
297 }
298
38f8704e
DK
299 if (Log != nullptr)
300 Log->Done(desc);
301
a4b8112b
DK
302 // if we change site, treat it as a mirror change
303 if (URI::SiteOnly(NewURI) != URI::SiteOnly(desc.URI))
304 {
84ac6edf
DK
305 auto const firstSpace = desc.Description.find(" ");
306 if (firstSpace != std::string::npos)
a4b8112b 307 {
84ac6edf
DK
308 std::string const OldSite = desc.Description.substr(0, firstSpace);
309 if (likely(APT::String::Startswith(desc.URI, OldSite)))
a4b8112b 310 {
84ac6edf
DK
311 std::string const OldExtra = desc.URI.substr(OldSite.length() + 1);
312 if (likely(APT::String::Endswith(NewURI, OldExtra)))
313 {
314 std::string const NewSite = NewURI.substr(0, NewURI.length() - OldExtra.length());
315 Owner->UsedMirror = URI::ArchiveOnly(NewSite);
316 desc.Description.replace(0, firstSpace, Owner->UsedMirror);
317 }
a4b8112b
DK
318 }
319 }
320 }
08ea7806 321 desc.URI = NewURI;
38f8704e
DK
322 if (isDoomedItem(Owner) == false)
323 OwnerQ->Owner->Enqueue(desc);
08ea7806 324 }
15d7e515
MV
325 break;
326 }
38f8704e
DK
327
328 case MessageType::WARNING:
421807e1 329 _error->Warning("%s: %s", Itm->Owner->DescURI().c_str(), LookupTag(Message,"Message").c_str());
8c9b7725 330 break;
448c38bd 331
38f8704e 332 case MessageType::URI_START:
c88edf1d 333 {
38f8704e 334 if (Itm == nullptr)
c88edf1d 335 {
93bf083d 336 _error->Error("Method gave invalid 200 URI Start message");
c88edf1d
AL
337 break;
338 }
448c38bd 339
c88edf1d
AL
340 CurrentItem = Itm;
341 CurrentSize = 0;
650faab0
DK
342 TotalSize = strtoull(LookupTag(Message,"Size","0").c_str(), NULL, 10);
343 ResumePoint = strtoull(LookupTag(Message,"Resume-Point","0").c_str(), NULL, 10);
38f8704e 344 for (auto const Owner: Itm->Owners)
08ea7806 345 {
38f8704e 346 Owner->Start(Message, TotalSize);
08ea7806 347 // Display update before completion
38f8704e 348 if (Log != nullptr)
08ea7806
DK
349 {
350 if (Log->MorePulses == true)
38f8704e
DK
351 Log->Pulse(Owner->GetOwner());
352 Log->Fetch(Owner->GetItemDesc());
08ea7806
DK
353 }
354 }
8267fe24 355
c88edf1d
AL
356 break;
357 }
448c38bd 358
38f8704e 359 case MessageType::URI_DONE:
c88edf1d 360 {
38f8704e 361 if (Itm == nullptr)
c88edf1d 362 {
93bf083d 363 _error->Error("Method gave invalid 201 URI Done message");
c88edf1d
AL
364 break;
365 }
448c38bd 366
08ea7806 367 PrepareFiles("201::URIDone", Itm);
359e1c4f 368
c5ccf175
AL
369 // Display update before completion
370 if (Log != 0 && Log->MorePulses == true)
08ea7806
DK
371 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
372 Log->Pulse((*O)->GetOwner());
448c38bd 373
20801f61 374 HashStringList ReceivedHashes;
8a8feb29 375 {
b6a0018e
DK
376 std::string const givenfilename = LookupTag(Message, "Filename");
377 std::string const filename = givenfilename.empty() ? Itm->Owner->DestFile : givenfilename;
08ea7806
DK
378 // see if we got hashes to verify
379 for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
448c38bd 380 {
08ea7806
DK
381 std::string const tagname = std::string(*type) + "-Hash";
382 std::string const hashsum = LookupTag(Message, tagname.c_str());
383 if (hashsum.empty() == false)
384 ReceivedHashes.push_back(HashString(*type, hashsum));
385 }
386 // not all methods always sent Hashes our way
387 if (ReceivedHashes.usable() == false)
388 {
389 HashStringList const ExpectedHashes = Itm->GetExpectedHashes();
390 if (ExpectedHashes.usable() == true && RealFileExists(filename))
391 {
392 Hashes calc(ExpectedHashes);
393 FileFd file(filename, FileFd::ReadOnly, FileFd::None);
394 calc.AddFD(file);
395 ReceivedHashes = calc.GetHashStringList();
396 }
448c38bd 397 }
b3501edb 398
b6a0018e
DK
399 // only local files can refer other filenames and counting them as fetched would be unfair
400 if (Log != NULL && Itm->Owner->Complete == false && Itm->Owner->Local == false && givenfilename == filename)
401 Log->Fetched(ReceivedHashes.FileSize(),atoi(LookupTag(Message,"Resume-Point","0").c_str()));
402 }
08ea7806
DK
403
404 std::vector<Item*> const ItmOwners = Itm->Owners;
405 OwnerQ->ItemDone(Itm);
406 Itm = NULL;
b3501edb 407
448c38bd
DK
408 bool const isIMSHit = StringToBool(LookupTag(Message,"IMS-Hit"),false) ||
409 StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false);
d03b947b 410 auto const forcedHash = _config->Find("Acquire::ForceHash");
38f8704e 411 for (auto const Owner: ItmOwners)
8267fe24 412 {
08ea7806
DK
413 HashStringList const ExpectedHashes = Owner->GetExpectedHashes();
414 if(_config->FindB("Debug::pkgAcquire::Auth", false) == true)
c46824ce 415 {
08ea7806
DK
416 std::clog << "201 URI Done: " << Owner->DescURI() << endl
417 << "ReceivedHash:" << endl;
418 for (HashStringList::const_iterator hs = ReceivedHashes.begin(); hs != ReceivedHashes.end(); ++hs)
419 std::clog << "\t- " << hs->toStr() << std::endl;
420 std::clog << "ExpectedHash:" << endl;
421 for (HashStringList::const_iterator hs = ExpectedHashes.begin(); hs != ExpectedHashes.end(); ++hs)
422 std::clog << "\t- " << hs->toStr() << std::endl;
423 std::clog << endl;
448c38bd 424 }
448c38bd 425
08ea7806
DK
426 // decide if what we got is what we expected
427 bool consideredOkay = false;
d03b947b
DK
428 if ((forcedHash.empty() && ExpectedHashes.empty() == false) ||
429 (forcedHash.empty() == false && ExpectedHashes.usable()))
08ea7806 430 {
d03b947b 431 if (ReceivedHashes.empty())
08ea7806
DK
432 {
433 /* IMS-Hits can't be checked here as we will have uncompressed file,
434 but the hashes for the compressed file. What we have was good through
435 so all we have to ensure later is that we are not stalled. */
436 consideredOkay = isIMSHit;
437 }
438 else if (ReceivedHashes == ExpectedHashes)
439 consideredOkay = true;
440 else
441 consideredOkay = false;
448c38bd 442
08ea7806 443 }
08ea7806 444 else
d03b947b 445 consideredOkay = !Owner->HashesRequired();
448c38bd 446
dd676dc7
DK
447 if (consideredOkay == true)
448 consideredOkay = Owner->VerifyDone(Message, Config);
449 else // hashsum mismatch
450 Owner->Status = pkgAcquire::Item::StatAuthError;
451
38f8704e 452
08ea7806 453 if (consideredOkay == true)
448c38bd 454 {
38f8704e
DK
455 if (isDoomedItem(Owner) == false)
456 Owner->Done(Message, ReceivedHashes, Config);
457 if (Log != nullptr)
448c38bd 458 {
08ea7806
DK
459 if (isIMSHit)
460 Log->IMSHit(Owner->GetItemDesc());
461 else
462 Log->Done(Owner->GetItemDesc());
448c38bd 463 }
448c38bd 464 }
08ea7806
DK
465 else
466 {
38f8704e 467 if (isDoomedItem(Owner) == false)
0340069c 468 {
562f0774
DK
469 if (Message.find("\nFailReason:") == std::string::npos)
470 {
471 if (ReceivedHashes != ExpectedHashes)
472 Message.append("\nFailReason: HashSumMismatch");
473 else
474 Message.append("\nFailReason: WeakHashSums");
475 }
38f8704e 476 Owner->Failed(Message,Config);
0340069c 477 }
38f8704e 478 if (Log != nullptr)
08ea7806
DK
479 Log->Fail(Owner->GetItemDesc());
480 }
18ef0a78 481 }
08ea7806 482 ItemDone();
c88edf1d 483 break;
448c38bd
DK
484 }
485
38f8704e 486 case MessageType::URI_FAILURE:
c88edf1d 487 {
38f8704e 488 if (Itm == nullptr)
c88edf1d 489 {
5684f71f
DK
490 std::string const msg = LookupTag(Message,"Message");
491 _error->Error("Method gave invalid 400 URI Failure message: %s", msg.c_str());
c88edf1d
AL
492 break;
493 }
494
08ea7806
DK
495 PrepareFiles("400::URIFailure", Itm);
496
c5ccf175 497 // Display update before completion
38f8704e 498 if (Log != nullptr && Log->MorePulses == true)
08ea7806
DK
499 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
500 Log->Pulse((*O)->GetOwner());
359e1c4f 501
08ea7806 502 std::vector<Item*> const ItmOwners = Itm->Owners;
c88edf1d 503 OwnerQ->ItemDone(Itm);
38f8704e 504 Itm = nullptr;
7e5f33eb 505
30979dd7 506 bool errTransient = false, errAuthErr = false;
9f301e0f
DK
507 {
508 std::string const failReason = LookupTag(Message, "FailReason");
30979dd7
DK
509 {
510 auto const reasons = { "Timeout", "ConnectionRefused",
511 "ConnectionTimedOut", "ResolveFailure", "TmpResolveFailure" };
512 errTransient = std::find(std::begin(reasons), std::end(reasons), failReason) != std::end(reasons);
513 }
514 if (errTransient == false)
515 {
562f0774 516 auto const reasons = { "HashSumMismatch", "WeakHashSums", "MaximumSizeExceeded" };
30979dd7
DK
517 errAuthErr = std::find(std::begin(reasons), std::end(reasons), failReason) != std::end(reasons);
518 }
9f301e0f
DK
519 }
520
38f8704e 521 for (auto const Owner: ItmOwners)
08ea7806 522 {
30979dd7
DK
523 if (errAuthErr && Owner->GetExpectedHashes().empty() == false)
524 Owner->Status = pkgAcquire::Item::StatAuthError;
525 else if (errTransient)
38f8704e 526 Owner->Status = pkgAcquire::Item::StatTransientNetworkError;
30979dd7 527
38f8704e
DK
528 if (isDoomedItem(Owner) == false)
529 Owner->Failed(Message,Config);
530 if (Log != nullptr)
531 Log->Fail(Owner->GetItemDesc());
08ea7806
DK
532 }
533 ItemDone();
7d8afa39 534
c88edf1d 535 break;
448c38bd
DK
536 }
537
38f8704e 538 case MessageType::GENERAL_FAILURE:
b2e465d6 539 _error->Error("Method %s General failure: %s",Access.c_str(),LookupTag(Message,"Message").c_str());
0a8a80e5 540 break;
448c38bd 541
38f8704e 542 case MessageType::MEDIA_CHANGE:
448c38bd 543 MediaChange(Message);
542ec555 544 break;
448c38bd 545 }
3b5421b4
AL
546 }
547 return true;
548}
549 /*}}}*/
550// Worker::Capabilities - 100 Capabilities handler /*{{{*/
551// ---------------------------------------------------------------------
552/* This parses the capabilities message and dumps it into the configuration
553 structure. */
554bool pkgAcquire::Worker::Capabilities(string Message)
555{
556 if (Config == 0)
557 return true;
448c38bd 558
3b5421b4
AL
559 Config->Version = LookupTag(Message,"Version");
560 Config->SingleInstance = StringToBool(LookupTag(Message,"Single-Instance"),false);
0a8a80e5
AL
561 Config->Pipeline = StringToBool(LookupTag(Message,"Pipeline"),false);
562 Config->SendConfig = StringToBool(LookupTag(Message,"Send-Config"),false);
e331f6ed 563 Config->LocalOnly = StringToBool(LookupTag(Message,"Local-Only"),false);
8e5fc8f5 564 Config->NeedsCleanup = StringToBool(LookupTag(Message,"Needs-Cleanup"),false);
459681d3 565 Config->Removable = StringToBool(LookupTag(Message,"Removable"),false);
3b5421b4
AL
566
567 // Some debug text
568 if (Debug == true)
569 {
570 clog << "Configured access method " << Config->Access << endl;
459681d3
AL
571 clog << "Version:" << Config->Version <<
572 " SingleInstance:" << Config->SingleInstance <<
448c38bd
DK
573 " Pipeline:" << Config->Pipeline <<
574 " SendConfig:" << Config->SendConfig <<
575 " LocalOnly: " << Config->LocalOnly <<
576 " NeedsCleanup: " << Config->NeedsCleanup <<
459681d3 577 " Removable: " << Config->Removable << endl;
3b5421b4 578 }
448c38bd 579
542ec555
AL
580 return true;
581}
582 /*}}}*/
583// Worker::MediaChange - Request a media change /*{{{*/
584// ---------------------------------------------------------------------
585/* */
586bool pkgAcquire::Worker::MediaChange(string Message)
587{
80a26ed1 588 int status_fd = _config->FindI("APT::Status-Fd",-1);
448c38bd 589 if(status_fd > 0)
80a26ed1
MV
590 {
591 string Media = LookupTag(Message,"Media");
448c38bd 592 string Drive = LookupTag(Message,"Drive");
80a26ed1 593 ostringstream msg,status;
1a82c63e
MV
594 ioprintf(msg,_("Please insert the disc labeled: "
595 "'%s' "
94171725 596 "in the drive '%s' and press [Enter]."),
1a82c63e 597 Media.c_str(),Drive.c_str());
80a26ed1 598 status << "media-change: " // message
1a82c63e
MV
599 << Media << ":" // media
600 << Drive << ":" // drive
601 << msg.str() // l10n message
80a26ed1 602 << endl;
31bda500
DK
603
604 std::string const dlstatus = status.str();
d68d65ad 605 FileFd::Write(status_fd, dlstatus.c_str(), dlstatus.size());
80a26ed1
MV
606 }
607
542ec555
AL
608 if (Log == 0 || Log->MediaChange(LookupTag(Message,"Media"),
609 LookupTag(Message,"Drive")) == false)
610 {
611 char S[300];
96bc43c4 612 snprintf(S,sizeof(S),"603 Media Changed\nFailed: true\n\n");
542ec555
AL
613 if (Debug == true)
614 clog << " -> " << Access << ':' << QuoteString(S,"\n") << endl;
615 OutQueue += S;
616 OutReady = true;
617 return true;
618 }
619
620 char S[300];
96bc43c4 621 snprintf(S,sizeof(S),"603 Media Changed\n\n");
542ec555
AL
622 if (Debug == true)
623 clog << " -> " << Access << ':' << QuoteString(S,"\n") << endl;
624 OutQueue += S;
625 OutReady = true;
3b5421b4
AL
626 return true;
627}
0118833a 628 /*}}}*/
0a8a80e5
AL
629// Worker::SendConfiguration - Send the config to the method /*{{{*/
630// ---------------------------------------------------------------------
631/* */
632bool pkgAcquire::Worker::SendConfiguration()
633{
634 if (Config->SendConfig == false)
635 return true;
636
637 if (OutFd == -1)
638 return false;
0a8a80e5 639
d280d03a 640 /* Write out all of the configuration directives by walking the
0a8a80e5 641 configuration tree */
d280d03a
DK
642 std::ostringstream Message;
643 Message << "601 Configuration\n";
644 _config->Dump(Message, NULL, "Config-Item: %F=%V\n", false);
645 Message << '\n';
0a8a80e5
AL
646
647 if (Debug == true)
d280d03a
DK
648 clog << " -> " << Access << ':' << QuoteString(Message.str(),"\n") << endl;
649 OutQueue += Message.str();
650 OutReady = true;
651
0a8a80e5
AL
652 return true;
653}
654 /*}}}*/
655// Worker::QueueItem - Add an item to the outbound queue /*{{{*/
656// ---------------------------------------------------------------------
657/* Send a URI Acquire message to the method */
658bool pkgAcquire::Worker::QueueItem(pkgAcquire::Queue::QItem *Item)
659{
660 if (OutFd == -1)
661 return false;
448c38bd 662
562f0774
DK
663 HashStringList const hsl = Item->GetExpectedHashes();
664
665 if (isDoomedItem(Item->Owner))
666 return true;
667
668 if (hsl.usable() == false && Item->Owner->HashesRequired() &&
669 _config->Exists("Acquire::ForceHash") == false)
670 {
671 std::string const Message = "400 URI Failure"
672 "\nURI: " + Item->URI +
673 "\nFilename: " + Item->Owner->DestFile +
674 "\nFailReason: WeakHashSums";
675
676 auto const ItmOwners = Item->Owners;
677 for (auto &O: ItmOwners)
678 {
679 O->Status = pkgAcquire::Item::StatAuthError;
680 O->Failed(Message, Config);
681 if (Log != nullptr)
682 Log->Fail(O->GetItemDesc());
683 }
684 // "queued" successfully, the item just instantly failed
685 return true;
686 }
687
0a8a80e5
AL
688 string Message = "600 URI Acquire\n";
689 Message.reserve(300);
690 Message += "URI: " + Item->URI;
691 Message += "\nFilename: " + Item->Owner->DestFile;
08ea7806 692
d003a557
DK
693 for (HashStringList::const_iterator hs = hsl.begin(); hs != hsl.end(); ++hs)
694 Message += "\nExpected-" + hs->HashType() + ": " + hs->HashValue();
08ea7806
DK
695
696 if (hsl.FileSize() == 0)
c48eea97 697 {
08ea7806
DK
698 unsigned long long FileSize = Item->GetMaximumSize();
699 if(FileSize > 0)
700 {
701 string MaximumSize;
702 strprintf(MaximumSize, "%llu", FileSize);
703 Message += "\nMaximum-Size: " + MaximumSize;
704 }
c48eea97 705 }
08ea7806
DK
706
707 Item->SyncDestinationFiles();
708 Message += Item->Custom600Headers();
0a8a80e5 709 Message += "\n\n";
359e1c4f
DK
710
711 if (RealFileExists(Item->Owner->DestFile))
712 {
514a25cb 713 std::string const SandboxUser = _config->Find("APT::Sandbox::User");
359e1c4f
DK
714 ChangeOwnerAndPermissionOfFile("Item::QueueURI", Item->Owner->DestFile.c_str(),
715 SandboxUser.c_str(), "root", 0600);
716 }
717
0a8a80e5
AL
718 if (Debug == true)
719 clog << " -> " << Access << ':' << QuoteString(Message,"\n") << endl;
720 OutQueue += Message;
721 OutReady = true;
448c38bd 722
0a8a80e5
AL
723 return true;
724}
725 /*}}}*/
726// Worker::OutFdRead - Out bound FD is ready /*{{{*/
727// ---------------------------------------------------------------------
728/* */
729bool pkgAcquire::Worker::OutFdReady()
730{
ee7af1bd
YY
731 int Res;
732 do
733 {
734 Res = write(OutFd,OutQueue.c_str(),OutQueue.length());
735 }
736 while (Res < 0 && errno == EINTR);
737
738 if (Res <= 0)
0a8a80e5 739 return MethodFailure();
ee7af1bd
YY
740
741 OutQueue.erase(0,Res);
0a8a80e5
AL
742 if (OutQueue.empty() == true)
743 OutReady = false;
448c38bd 744
0a8a80e5
AL
745 return true;
746}
747 /*}}}*/
748// Worker::InFdRead - In bound FD is ready /*{{{*/
749// ---------------------------------------------------------------------
750/* */
751bool pkgAcquire::Worker::InFdReady()
752{
753 if (ReadMessages() == false)
754 return false;
755 RunMessages();
756 return true;
757}
758 /*}}}*/
759// Worker::MethodFailure - Called when the method fails /*{{{*/
760// ---------------------------------------------------------------------
1e3f4083 761/* This is called when the method is believed to have failed, probably because
0a8a80e5
AL
762 read returned -1. */
763bool pkgAcquire::Worker::MethodFailure()
764{
76d97c26 765 _error->Error("Method %s has died unexpectedly!",Access.c_str());
448c38bd 766
ab7f4d7c
MV
767 // do not reap the child here to show meaningfull error to the user
768 ExecWait(Process,Access.c_str(),false);
0a8a80e5
AL
769 Process = -1;
770 close(InFd);
771 close(OutFd);
772 InFd = -1;
773 OutFd = -1;
774 OutReady = false;
775 InReady = false;
776 OutQueue = string();
777 MessageQueue.erase(MessageQueue.begin(),MessageQueue.end());
448c38bd 778
0a8a80e5
AL
779 return false;
780}
781 /*}}}*/
448c38bd 782// Worker::Pulse - Called periodically /*{{{*/
8267fe24
AL
783// ---------------------------------------------------------------------
784/* */
785void pkgAcquire::Worker::Pulse()
786{
787 if (CurrentItem == 0)
788 return;
448c38bd 789
8267fe24
AL
790 struct stat Buf;
791 if (stat(CurrentItem->Owner->DestFile.c_str(),&Buf) != 0)
792 return;
793 CurrentSize = Buf.st_size;
794}
795 /*}}}*/
796// Worker::ItemDone - Called when the current item is finished /*{{{*/
797// ---------------------------------------------------------------------
798/* */
799void pkgAcquire::Worker::ItemDone()
800{
801 CurrentItem = 0;
802 CurrentSize = 0;
803 TotalSize = 0;
804 Status = string();
805}
806 /*}}}*/
08ea7806
DK
807void pkgAcquire::Worker::PrepareFiles(char const * const caller, pkgAcquire::Queue::QItem const * const Itm)/*{{{*/
808{
809 if (RealFileExists(Itm->Owner->DestFile))
810 {
811 ChangeOwnerAndPermissionOfFile(caller, Itm->Owner->DestFile.c_str(), "root", "root", 0644);
812 std::string const filename = Itm->Owner->DestFile;
813 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
814 {
815 pkgAcquire::Item const * const Owner = *O;
ce1f3a2c 816 if (Owner->DestFile == filename || filename == "/dev/null")
08ea7806 817 continue;
ce1f3a2c 818 RemoveFile("PrepareFiles", Owner->DestFile);
08ea7806
DK
819 if (link(filename.c_str(), Owner->DestFile.c_str()) != 0)
820 {
3d8232bf 821 // different mounts can't happen for us as we download to lists/ by default,
08ea7806
DK
822 // but if the system is reused by others the locations can potentially be on
823 // different disks, so use symlink as poor-men replacement.
824 // FIXME: Real copying as last fallback, but that is costly, so offload to a method preferable
825 if (symlink(filename.c_str(), Owner->DestFile.c_str()) != 0)
826 _error->Error("Can't create (sym)link of file %s to %s", filename.c_str(), Owner->DestFile.c_str());
827 }
828 }
829 }
830 else
831 {
832 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
ce1f3a2c 833 RemoveFile("PrepareFiles", (*O)->DestFile);
08ea7806
DK
834 }
835}
836 /*}}}*/