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