]> git.saurik.com Git - apt.git/blame - apt-pkg/acquire-worker.cc
test: Use :$(id -gn) instead of :root (when run as root)
[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 {
850ad026 467 auto SavedDesc = Owner->GetItemDesc();
38f8704e 468 if (isDoomedItem(Owner) == false)
0340069c 469 {
562f0774
DK
470 if (Message.find("\nFailReason:") == std::string::npos)
471 {
472 if (ReceivedHashes != ExpectedHashes)
473 Message.append("\nFailReason: HashSumMismatch");
474 else
475 Message.append("\nFailReason: WeakHashSums");
476 }
38f8704e 477 Owner->Failed(Message,Config);
0340069c 478 }
38f8704e 479 if (Log != nullptr)
850ad026 480 Log->Fail(SavedDesc);
08ea7806 481 }
18ef0a78 482 }
08ea7806 483 ItemDone();
c88edf1d 484 break;
448c38bd
DK
485 }
486
38f8704e 487 case MessageType::URI_FAILURE:
c88edf1d 488 {
38f8704e 489 if (Itm == nullptr)
c88edf1d 490 {
5684f71f
DK
491 std::string const msg = LookupTag(Message,"Message");
492 _error->Error("Method gave invalid 400 URI Failure message: %s", msg.c_str());
c88edf1d
AL
493 break;
494 }
495
08ea7806
DK
496 PrepareFiles("400::URIFailure", Itm);
497
c5ccf175 498 // Display update before completion
38f8704e 499 if (Log != nullptr && Log->MorePulses == true)
08ea7806
DK
500 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
501 Log->Pulse((*O)->GetOwner());
359e1c4f 502
08ea7806 503 std::vector<Item*> const ItmOwners = Itm->Owners;
c88edf1d 504 OwnerQ->ItemDone(Itm);
38f8704e 505 Itm = nullptr;
7e5f33eb 506
30979dd7 507 bool errTransient = false, errAuthErr = false;
9f301e0f
DK
508 {
509 std::string const failReason = LookupTag(Message, "FailReason");
30979dd7
DK
510 {
511 auto const reasons = { "Timeout", "ConnectionRefused",
512 "ConnectionTimedOut", "ResolveFailure", "TmpResolveFailure" };
513 errTransient = std::find(std::begin(reasons), std::end(reasons), failReason) != std::end(reasons);
514 }
515 if (errTransient == false)
516 {
562f0774 517 auto const reasons = { "HashSumMismatch", "WeakHashSums", "MaximumSizeExceeded" };
30979dd7
DK
518 errAuthErr = std::find(std::begin(reasons), std::end(reasons), failReason) != std::end(reasons);
519 }
9f301e0f
DK
520 }
521
38f8704e 522 for (auto const Owner: ItmOwners)
08ea7806 523 {
30979dd7
DK
524 if (errAuthErr && Owner->GetExpectedHashes().empty() == false)
525 Owner->Status = pkgAcquire::Item::StatAuthError;
526 else if (errTransient)
38f8704e 527 Owner->Status = pkgAcquire::Item::StatTransientNetworkError;
850ad026 528 auto SavedDesc = Owner->GetItemDesc();
38f8704e
DK
529 if (isDoomedItem(Owner) == false)
530 Owner->Failed(Message,Config);
531 if (Log != nullptr)
850ad026 532 Log->Fail(SavedDesc);
08ea7806
DK
533 }
534 ItemDone();
7d8afa39 535
c88edf1d 536 break;
448c38bd
DK
537 }
538
38f8704e 539 case MessageType::GENERAL_FAILURE:
b2e465d6 540 _error->Error("Method %s General failure: %s",Access.c_str(),LookupTag(Message,"Message").c_str());
0a8a80e5 541 break;
448c38bd 542
38f8704e 543 case MessageType::MEDIA_CHANGE:
448c38bd 544 MediaChange(Message);
542ec555 545 break;
448c38bd 546 }
3b5421b4
AL
547 }
548 return true;
549}
550 /*}}}*/
551// Worker::Capabilities - 100 Capabilities handler /*{{{*/
552// ---------------------------------------------------------------------
553/* This parses the capabilities message and dumps it into the configuration
554 structure. */
555bool pkgAcquire::Worker::Capabilities(string Message)
556{
557 if (Config == 0)
558 return true;
448c38bd 559
3b5421b4
AL
560 Config->Version = LookupTag(Message,"Version");
561 Config->SingleInstance = StringToBool(LookupTag(Message,"Single-Instance"),false);
0a8a80e5
AL
562 Config->Pipeline = StringToBool(LookupTag(Message,"Pipeline"),false);
563 Config->SendConfig = StringToBool(LookupTag(Message,"Send-Config"),false);
e331f6ed 564 Config->LocalOnly = StringToBool(LookupTag(Message,"Local-Only"),false);
8e5fc8f5 565 Config->NeedsCleanup = StringToBool(LookupTag(Message,"Needs-Cleanup"),false);
459681d3 566 Config->Removable = StringToBool(LookupTag(Message,"Removable"),false);
3b5421b4
AL
567
568 // Some debug text
569 if (Debug == true)
570 {
571 clog << "Configured access method " << Config->Access << endl;
459681d3
AL
572 clog << "Version:" << Config->Version <<
573 " SingleInstance:" << Config->SingleInstance <<
448c38bd
DK
574 " Pipeline:" << Config->Pipeline <<
575 " SendConfig:" << Config->SendConfig <<
576 " LocalOnly: " << Config->LocalOnly <<
577 " NeedsCleanup: " << Config->NeedsCleanup <<
459681d3 578 " Removable: " << Config->Removable << endl;
3b5421b4 579 }
448c38bd 580
542ec555
AL
581 return true;
582}
583 /*}}}*/
584// Worker::MediaChange - Request a media change /*{{{*/
585// ---------------------------------------------------------------------
586/* */
587bool pkgAcquire::Worker::MediaChange(string Message)
588{
80a26ed1 589 int status_fd = _config->FindI("APT::Status-Fd",-1);
448c38bd 590 if(status_fd > 0)
80a26ed1
MV
591 {
592 string Media = LookupTag(Message,"Media");
448c38bd 593 string Drive = LookupTag(Message,"Drive");
80a26ed1 594 ostringstream msg,status;
1a82c63e
MV
595 ioprintf(msg,_("Please insert the disc labeled: "
596 "'%s' "
94171725 597 "in the drive '%s' and press [Enter]."),
1a82c63e 598 Media.c_str(),Drive.c_str());
80a26ed1 599 status << "media-change: " // message
1a82c63e
MV
600 << Media << ":" // media
601 << Drive << ":" // drive
602 << msg.str() // l10n message
80a26ed1 603 << endl;
31bda500
DK
604
605 std::string const dlstatus = status.str();
d68d65ad 606 FileFd::Write(status_fd, dlstatus.c_str(), dlstatus.size());
80a26ed1
MV
607 }
608
542ec555
AL
609 if (Log == 0 || Log->MediaChange(LookupTag(Message,"Media"),
610 LookupTag(Message,"Drive")) == false)
611 {
612 char S[300];
96bc43c4 613 snprintf(S,sizeof(S),"603 Media Changed\nFailed: true\n\n");
542ec555
AL
614 if (Debug == true)
615 clog << " -> " << Access << ':' << QuoteString(S,"\n") << endl;
616 OutQueue += S;
617 OutReady = true;
618 return true;
619 }
620
621 char S[300];
96bc43c4 622 snprintf(S,sizeof(S),"603 Media Changed\n\n");
542ec555
AL
623 if (Debug == true)
624 clog << " -> " << Access << ':' << QuoteString(S,"\n") << endl;
625 OutQueue += S;
626 OutReady = true;
3b5421b4
AL
627 return true;
628}
0118833a 629 /*}}}*/
0a8a80e5
AL
630// Worker::SendConfiguration - Send the config to the method /*{{{*/
631// ---------------------------------------------------------------------
632/* */
633bool pkgAcquire::Worker::SendConfiguration()
634{
635 if (Config->SendConfig == false)
636 return true;
637
638 if (OutFd == -1)
639 return false;
0a8a80e5 640
d280d03a 641 /* Write out all of the configuration directives by walking the
0a8a80e5 642 configuration tree */
d280d03a
DK
643 std::ostringstream Message;
644 Message << "601 Configuration\n";
645 _config->Dump(Message, NULL, "Config-Item: %F=%V\n", false);
646 Message << '\n';
0a8a80e5
AL
647
648 if (Debug == true)
d280d03a
DK
649 clog << " -> " << Access << ':' << QuoteString(Message.str(),"\n") << endl;
650 OutQueue += Message.str();
651 OutReady = true;
652
0a8a80e5
AL
653 return true;
654}
655 /*}}}*/
656// Worker::QueueItem - Add an item to the outbound queue /*{{{*/
657// ---------------------------------------------------------------------
658/* Send a URI Acquire message to the method */
659bool pkgAcquire::Worker::QueueItem(pkgAcquire::Queue::QItem *Item)
660{
661 if (OutFd == -1)
662 return false;
448c38bd 663
562f0774
DK
664 HashStringList const hsl = Item->GetExpectedHashes();
665
666 if (isDoomedItem(Item->Owner))
667 return true;
668
669 if (hsl.usable() == false && Item->Owner->HashesRequired() &&
670 _config->Exists("Acquire::ForceHash") == false)
671 {
672 std::string const Message = "400 URI Failure"
673 "\nURI: " + Item->URI +
674 "\nFilename: " + Item->Owner->DestFile +
675 "\nFailReason: WeakHashSums";
676
677 auto const ItmOwners = Item->Owners;
678 for (auto &O: ItmOwners)
679 {
680 O->Status = pkgAcquire::Item::StatAuthError;
681 O->Failed(Message, Config);
682 if (Log != nullptr)
683 Log->Fail(O->GetItemDesc());
684 }
685 // "queued" successfully, the item just instantly failed
686 return true;
687 }
688
18ccc85f
DK
689 if (Item->Owner->IsRedirectionLoop(Item->URI))
690 {
691 std::string const Message = "400 URI Failure"
692 "\nURI: " + Item->URI +
693 "\nFilename: " + Item->Owner->DestFile +
694 "\nFailReason: RedirectionLoop";
695
696 auto const ItmOwners = Item->Owners;
697 for (auto &O: ItmOwners)
698 {
699 O->Status = pkgAcquire::Item::StatError;
700 O->Failed(Message, Config);
701 if (Log != nullptr)
702 Log->Fail(O->GetItemDesc());
703 }
704 // "queued" successfully, the item just instantly failed
705 return true;
706 }
707
0a8a80e5
AL
708 string Message = "600 URI Acquire\n";
709 Message.reserve(300);
710 Message += "URI: " + Item->URI;
711 Message += "\nFilename: " + Item->Owner->DestFile;
08ea7806 712
d003a557
DK
713 for (HashStringList::const_iterator hs = hsl.begin(); hs != hsl.end(); ++hs)
714 Message += "\nExpected-" + hs->HashType() + ": " + hs->HashValue();
08ea7806
DK
715
716 if (hsl.FileSize() == 0)
c48eea97 717 {
08ea7806
DK
718 unsigned long long FileSize = Item->GetMaximumSize();
719 if(FileSize > 0)
720 {
721 string MaximumSize;
722 strprintf(MaximumSize, "%llu", FileSize);
723 Message += "\nMaximum-Size: " + MaximumSize;
724 }
c48eea97 725 }
08ea7806
DK
726
727 Item->SyncDestinationFiles();
728 Message += Item->Custom600Headers();
0a8a80e5 729 Message += "\n\n";
359e1c4f
DK
730
731 if (RealFileExists(Item->Owner->DestFile))
732 {
514a25cb 733 std::string const SandboxUser = _config->Find("APT::Sandbox::User");
359e1c4f
DK
734 ChangeOwnerAndPermissionOfFile("Item::QueueURI", Item->Owner->DestFile.c_str(),
735 SandboxUser.c_str(), "root", 0600);
736 }
737
0a8a80e5
AL
738 if (Debug == true)
739 clog << " -> " << Access << ':' << QuoteString(Message,"\n") << endl;
740 OutQueue += Message;
741 OutReady = true;
448c38bd 742
0a8a80e5
AL
743 return true;
744}
745 /*}}}*/
746// Worker::OutFdRead - Out bound FD is ready /*{{{*/
747// ---------------------------------------------------------------------
748/* */
749bool pkgAcquire::Worker::OutFdReady()
750{
ee7af1bd
YY
751 int Res;
752 do
753 {
754 Res = write(OutFd,OutQueue.c_str(),OutQueue.length());
755 }
756 while (Res < 0 && errno == EINTR);
757
758 if (Res <= 0)
0a8a80e5 759 return MethodFailure();
ee7af1bd
YY
760
761 OutQueue.erase(0,Res);
0a8a80e5
AL
762 if (OutQueue.empty() == true)
763 OutReady = false;
448c38bd 764
0a8a80e5
AL
765 return true;
766}
767 /*}}}*/
768// Worker::InFdRead - In bound FD is ready /*{{{*/
769// ---------------------------------------------------------------------
770/* */
771bool pkgAcquire::Worker::InFdReady()
772{
773 if (ReadMessages() == false)
774 return false;
775 RunMessages();
776 return true;
777}
778 /*}}}*/
779// Worker::MethodFailure - Called when the method fails /*{{{*/
780// ---------------------------------------------------------------------
1e3f4083 781/* This is called when the method is believed to have failed, probably because
0a8a80e5
AL
782 read returned -1. */
783bool pkgAcquire::Worker::MethodFailure()
784{
76d97c26 785 _error->Error("Method %s has died unexpectedly!",Access.c_str());
448c38bd 786
ab7f4d7c
MV
787 // do not reap the child here to show meaningfull error to the user
788 ExecWait(Process,Access.c_str(),false);
0a8a80e5
AL
789 Process = -1;
790 close(InFd);
791 close(OutFd);
792 InFd = -1;
793 OutFd = -1;
794 OutReady = false;
795 InReady = false;
796 OutQueue = string();
797 MessageQueue.erase(MessageQueue.begin(),MessageQueue.end());
448c38bd 798
0a8a80e5
AL
799 return false;
800}
801 /*}}}*/
448c38bd 802// Worker::Pulse - Called periodically /*{{{*/
8267fe24
AL
803// ---------------------------------------------------------------------
804/* */
805void pkgAcquire::Worker::Pulse()
806{
807 if (CurrentItem == 0)
808 return;
448c38bd 809
8267fe24
AL
810 struct stat Buf;
811 if (stat(CurrentItem->Owner->DestFile.c_str(),&Buf) != 0)
812 return;
813 CurrentSize = Buf.st_size;
814}
815 /*}}}*/
816// Worker::ItemDone - Called when the current item is finished /*{{{*/
817// ---------------------------------------------------------------------
818/* */
819void pkgAcquire::Worker::ItemDone()
820{
821 CurrentItem = 0;
822 CurrentSize = 0;
823 TotalSize = 0;
824 Status = string();
825}
826 /*}}}*/
08ea7806
DK
827void pkgAcquire::Worker::PrepareFiles(char const * const caller, pkgAcquire::Queue::QItem const * const Itm)/*{{{*/
828{
829 if (RealFileExists(Itm->Owner->DestFile))
830 {
831 ChangeOwnerAndPermissionOfFile(caller, Itm->Owner->DestFile.c_str(), "root", "root", 0644);
832 std::string const filename = Itm->Owner->DestFile;
833 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
834 {
835 pkgAcquire::Item const * const Owner = *O;
ce1f3a2c 836 if (Owner->DestFile == filename || filename == "/dev/null")
08ea7806 837 continue;
ce1f3a2c 838 RemoveFile("PrepareFiles", Owner->DestFile);
08ea7806
DK
839 if (link(filename.c_str(), Owner->DestFile.c_str()) != 0)
840 {
3d8232bf 841 // different mounts can't happen for us as we download to lists/ by default,
08ea7806
DK
842 // but if the system is reused by others the locations can potentially be on
843 // different disks, so use symlink as poor-men replacement.
844 // FIXME: Real copying as last fallback, but that is costly, so offload to a method preferable
845 if (symlink(filename.c_str(), Owner->DestFile.c_str()) != 0)
846 _error->Error("Can't create (sym)link of file %s to %s", filename.c_str(), Owner->DestFile.c_str());
847 }
848 }
849 }
850 else
851 {
852 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
ce1f3a2c 853 RemoveFile("PrepareFiles", (*O)->DestFile);
08ea7806
DK
854 }
855}
856 /*}}}*/