]> git.saurik.com Git - apt.git/blame - apt-pkg/acquire-worker.cc
sanify unused ReportMirrorFailure a tiny bit
[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 {
276 std::string const OldSite = desc.Description.substr(0, desc.Description.find(" "));
277 if (likely(APT::String::Startswith(desc.URI, OldSite)))
278 {
279 std::string const OldExtra = desc.URI.substr(OldSite.length() + 1);
280 if (likely(APT::String::Endswith(NewURI, OldExtra)))
281 {
282 std::string const NewSite = NewURI.substr(0, NewURI.length() - OldExtra.length());
283 Owner->UsedMirror = URI::ArchiveOnly(NewSite);
284 if (desc.Description.find(" ") != string::npos)
285 desc.Description.replace(0, desc.Description.find(" "), Owner->UsedMirror);
286 }
287 }
288 }
08ea7806 289 desc.URI = NewURI;
38f8704e
DK
290 if (isDoomedItem(Owner) == false)
291 OwnerQ->Owner->Enqueue(desc);
08ea7806 292 }
15d7e515
MV
293 break;
294 }
38f8704e
DK
295
296 case MessageType::WARNING:
421807e1 297 _error->Warning("%s: %s", Itm->Owner->DescURI().c_str(), LookupTag(Message,"Message").c_str());
8c9b7725 298 break;
448c38bd 299
38f8704e 300 case MessageType::URI_START:
c88edf1d 301 {
38f8704e 302 if (Itm == nullptr)
c88edf1d 303 {
93bf083d 304 _error->Error("Method gave invalid 200 URI Start message");
c88edf1d
AL
305 break;
306 }
448c38bd 307
c88edf1d
AL
308 CurrentItem = Itm;
309 CurrentSize = 0;
650faab0
DK
310 TotalSize = strtoull(LookupTag(Message,"Size","0").c_str(), NULL, 10);
311 ResumePoint = strtoull(LookupTag(Message,"Resume-Point","0").c_str(), NULL, 10);
38f8704e 312 for (auto const Owner: Itm->Owners)
08ea7806 313 {
38f8704e 314 Owner->Start(Message, TotalSize);
08ea7806 315 // Display update before completion
38f8704e 316 if (Log != nullptr)
08ea7806
DK
317 {
318 if (Log->MorePulses == true)
38f8704e
DK
319 Log->Pulse(Owner->GetOwner());
320 Log->Fetch(Owner->GetItemDesc());
08ea7806
DK
321 }
322 }
8267fe24 323
c88edf1d
AL
324 break;
325 }
448c38bd 326
38f8704e 327 case MessageType::URI_DONE:
c88edf1d 328 {
38f8704e 329 if (Itm == nullptr)
c88edf1d 330 {
93bf083d 331 _error->Error("Method gave invalid 201 URI Done message");
c88edf1d
AL
332 break;
333 }
448c38bd 334
08ea7806 335 PrepareFiles("201::URIDone", Itm);
359e1c4f 336
c5ccf175
AL
337 // Display update before completion
338 if (Log != 0 && Log->MorePulses == true)
08ea7806
DK
339 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
340 Log->Pulse((*O)->GetOwner());
448c38bd 341
20801f61 342 HashStringList ReceivedHashes;
8a8feb29 343 {
b6a0018e
DK
344 std::string const givenfilename = LookupTag(Message, "Filename");
345 std::string const filename = givenfilename.empty() ? Itm->Owner->DestFile : givenfilename;
08ea7806
DK
346 // see if we got hashes to verify
347 for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
448c38bd 348 {
08ea7806
DK
349 std::string const tagname = std::string(*type) + "-Hash";
350 std::string const hashsum = LookupTag(Message, tagname.c_str());
351 if (hashsum.empty() == false)
352 ReceivedHashes.push_back(HashString(*type, hashsum));
353 }
354 // not all methods always sent Hashes our way
355 if (ReceivedHashes.usable() == false)
356 {
357 HashStringList const ExpectedHashes = Itm->GetExpectedHashes();
358 if (ExpectedHashes.usable() == true && RealFileExists(filename))
359 {
360 Hashes calc(ExpectedHashes);
361 FileFd file(filename, FileFd::ReadOnly, FileFd::None);
362 calc.AddFD(file);
363 ReceivedHashes = calc.GetHashStringList();
364 }
448c38bd 365 }
b3501edb 366
b6a0018e
DK
367 // only local files can refer other filenames and counting them as fetched would be unfair
368 if (Log != NULL && Itm->Owner->Complete == false && Itm->Owner->Local == false && givenfilename == filename)
369 Log->Fetched(ReceivedHashes.FileSize(),atoi(LookupTag(Message,"Resume-Point","0").c_str()));
370 }
08ea7806
DK
371
372 std::vector<Item*> const ItmOwners = Itm->Owners;
373 OwnerQ->ItemDone(Itm);
374 Itm = NULL;
b3501edb 375
448c38bd
DK
376 bool const isIMSHit = StringToBool(LookupTag(Message,"IMS-Hit"),false) ||
377 StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false);
38f8704e 378 for (auto const Owner: ItmOwners)
8267fe24 379 {
08ea7806
DK
380 HashStringList const ExpectedHashes = Owner->GetExpectedHashes();
381 if(_config->FindB("Debug::pkgAcquire::Auth", false) == true)
c46824ce 382 {
08ea7806
DK
383 std::clog << "201 URI Done: " << Owner->DescURI() << endl
384 << "ReceivedHash:" << endl;
385 for (HashStringList::const_iterator hs = ReceivedHashes.begin(); hs != ReceivedHashes.end(); ++hs)
386 std::clog << "\t- " << hs->toStr() << std::endl;
387 std::clog << "ExpectedHash:" << endl;
388 for (HashStringList::const_iterator hs = ExpectedHashes.begin(); hs != ExpectedHashes.end(); ++hs)
389 std::clog << "\t- " << hs->toStr() << std::endl;
390 std::clog << endl;
448c38bd 391 }
448c38bd 392
08ea7806
DK
393 // decide if what we got is what we expected
394 bool consideredOkay = false;
395 if (ExpectedHashes.usable())
396 {
397 if (ReceivedHashes.usable() == false)
398 {
399 /* IMS-Hits can't be checked here as we will have uncompressed file,
400 but the hashes for the compressed file. What we have was good through
401 so all we have to ensure later is that we are not stalled. */
402 consideredOkay = isIMSHit;
403 }
404 else if (ReceivedHashes == ExpectedHashes)
405 consideredOkay = true;
406 else
407 consideredOkay = false;
448c38bd 408
08ea7806
DK
409 }
410 else if (Owner->HashesRequired() == true)
411 consideredOkay = false;
412 else
63d60998 413 {
08ea7806 414 consideredOkay = true;
63d60998
DK
415 // even if the hashes aren't usable to declare something secure
416 // we can at least use them to declare it an integrity failure
417 if (ExpectedHashes.empty() == false && ReceivedHashes != ExpectedHashes && _config->Find("Acquire::ForceHash").empty())
418 consideredOkay = false;
419 }
448c38bd 420
dd676dc7
DK
421 if (consideredOkay == true)
422 consideredOkay = Owner->VerifyDone(Message, Config);
423 else // hashsum mismatch
424 Owner->Status = pkgAcquire::Item::StatAuthError;
425
38f8704e 426
08ea7806 427 if (consideredOkay == true)
448c38bd 428 {
38f8704e
DK
429 if (isDoomedItem(Owner) == false)
430 Owner->Done(Message, ReceivedHashes, Config);
431 if (Log != nullptr)
448c38bd 432 {
08ea7806
DK
433 if (isIMSHit)
434 Log->IMSHit(Owner->GetItemDesc());
435 else
436 Log->Done(Owner->GetItemDesc());
448c38bd 437 }
448c38bd 438 }
08ea7806
DK
439 else
440 {
38f8704e
DK
441 if (isDoomedItem(Owner) == false)
442 Owner->Failed(Message,Config);
443 if (Log != nullptr)
08ea7806
DK
444 Log->Fail(Owner->GetItemDesc());
445 }
18ef0a78 446 }
08ea7806 447 ItemDone();
c88edf1d 448 break;
448c38bd
DK
449 }
450
38f8704e 451 case MessageType::URI_FAILURE:
c88edf1d 452 {
38f8704e 453 if (Itm == nullptr)
c88edf1d 454 {
5684f71f
DK
455 std::string const msg = LookupTag(Message,"Message");
456 _error->Error("Method gave invalid 400 URI Failure message: %s", msg.c_str());
c88edf1d
AL
457 break;
458 }
459
08ea7806
DK
460 PrepareFiles("400::URIFailure", Itm);
461
c5ccf175 462 // Display update before completion
38f8704e 463 if (Log != nullptr && Log->MorePulses == true)
08ea7806
DK
464 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
465 Log->Pulse((*O)->GetOwner());
359e1c4f 466
08ea7806 467 std::vector<Item*> const ItmOwners = Itm->Owners;
c88edf1d 468 OwnerQ->ItemDone(Itm);
38f8704e 469 Itm = nullptr;
7e5f33eb 470
9f301e0f
DK
471 bool errTransient;
472 {
473 std::string const failReason = LookupTag(Message, "FailReason");
474 std::string const reasons[] = { "Timeout", "ConnectionRefused",
475 "ConnectionTimedOut", "ResolveFailure", "TmpResolveFailure" };
476 errTransient = std::find(std::begin(reasons), std::end(reasons), failReason) != std::end(reasons);
477 }
478
38f8704e 479 for (auto const Owner: ItmOwners)
08ea7806 480 {
9f301e0f 481 if (errTransient)
38f8704e
DK
482 Owner->Status = pkgAcquire::Item::StatTransientNetworkError;
483 if (isDoomedItem(Owner) == false)
484 Owner->Failed(Message,Config);
485 if (Log != nullptr)
486 Log->Fail(Owner->GetItemDesc());
08ea7806
DK
487 }
488 ItemDone();
7d8afa39 489
c88edf1d 490 break;
448c38bd
DK
491 }
492
38f8704e 493 case MessageType::GENERAL_FAILURE:
b2e465d6 494 _error->Error("Method %s General failure: %s",Access.c_str(),LookupTag(Message,"Message").c_str());
0a8a80e5 495 break;
448c38bd 496
38f8704e 497 case MessageType::MEDIA_CHANGE:
448c38bd 498 MediaChange(Message);
542ec555 499 break;
448c38bd 500 }
3b5421b4
AL
501 }
502 return true;
503}
504 /*}}}*/
505// Worker::Capabilities - 100 Capabilities handler /*{{{*/
506// ---------------------------------------------------------------------
507/* This parses the capabilities message and dumps it into the configuration
508 structure. */
509bool pkgAcquire::Worker::Capabilities(string Message)
510{
511 if (Config == 0)
512 return true;
448c38bd 513
3b5421b4
AL
514 Config->Version = LookupTag(Message,"Version");
515 Config->SingleInstance = StringToBool(LookupTag(Message,"Single-Instance"),false);
0a8a80e5
AL
516 Config->Pipeline = StringToBool(LookupTag(Message,"Pipeline"),false);
517 Config->SendConfig = StringToBool(LookupTag(Message,"Send-Config"),false);
e331f6ed 518 Config->LocalOnly = StringToBool(LookupTag(Message,"Local-Only"),false);
8e5fc8f5 519 Config->NeedsCleanup = StringToBool(LookupTag(Message,"Needs-Cleanup"),false);
459681d3 520 Config->Removable = StringToBool(LookupTag(Message,"Removable"),false);
3b5421b4
AL
521
522 // Some debug text
523 if (Debug == true)
524 {
525 clog << "Configured access method " << Config->Access << endl;
459681d3
AL
526 clog << "Version:" << Config->Version <<
527 " SingleInstance:" << Config->SingleInstance <<
448c38bd
DK
528 " Pipeline:" << Config->Pipeline <<
529 " SendConfig:" << Config->SendConfig <<
530 " LocalOnly: " << Config->LocalOnly <<
531 " NeedsCleanup: " << Config->NeedsCleanup <<
459681d3 532 " Removable: " << Config->Removable << endl;
3b5421b4 533 }
448c38bd 534
542ec555
AL
535 return true;
536}
537 /*}}}*/
538// Worker::MediaChange - Request a media change /*{{{*/
539// ---------------------------------------------------------------------
540/* */
541bool pkgAcquire::Worker::MediaChange(string Message)
542{
80a26ed1 543 int status_fd = _config->FindI("APT::Status-Fd",-1);
448c38bd 544 if(status_fd > 0)
80a26ed1
MV
545 {
546 string Media = LookupTag(Message,"Media");
448c38bd 547 string Drive = LookupTag(Message,"Drive");
80a26ed1 548 ostringstream msg,status;
1a82c63e
MV
549 ioprintf(msg,_("Please insert the disc labeled: "
550 "'%s' "
94171725 551 "in the drive '%s' and press [Enter]."),
1a82c63e 552 Media.c_str(),Drive.c_str());
80a26ed1 553 status << "media-change: " // message
1a82c63e
MV
554 << Media << ":" // media
555 << Drive << ":" // drive
556 << msg.str() // l10n message
80a26ed1 557 << endl;
31bda500
DK
558
559 std::string const dlstatus = status.str();
d68d65ad 560 FileFd::Write(status_fd, dlstatus.c_str(), dlstatus.size());
80a26ed1
MV
561 }
562
542ec555
AL
563 if (Log == 0 || Log->MediaChange(LookupTag(Message,"Media"),
564 LookupTag(Message,"Drive")) == false)
565 {
566 char S[300];
96bc43c4 567 snprintf(S,sizeof(S),"603 Media Changed\nFailed: true\n\n");
542ec555
AL
568 if (Debug == true)
569 clog << " -> " << Access << ':' << QuoteString(S,"\n") << endl;
570 OutQueue += S;
571 OutReady = true;
572 return true;
573 }
574
575 char S[300];
96bc43c4 576 snprintf(S,sizeof(S),"603 Media Changed\n\n");
542ec555
AL
577 if (Debug == true)
578 clog << " -> " << Access << ':' << QuoteString(S,"\n") << endl;
579 OutQueue += S;
580 OutReady = true;
3b5421b4
AL
581 return true;
582}
0118833a 583 /*}}}*/
0a8a80e5
AL
584// Worker::SendConfiguration - Send the config to the method /*{{{*/
585// ---------------------------------------------------------------------
586/* */
587bool pkgAcquire::Worker::SendConfiguration()
588{
589 if (Config->SendConfig == false)
590 return true;
591
592 if (OutFd == -1)
593 return false;
0a8a80e5 594
d280d03a 595 /* Write out all of the configuration directives by walking the
0a8a80e5 596 configuration tree */
d280d03a
DK
597 std::ostringstream Message;
598 Message << "601 Configuration\n";
599 _config->Dump(Message, NULL, "Config-Item: %F=%V\n", false);
600 Message << '\n';
0a8a80e5
AL
601
602 if (Debug == true)
d280d03a
DK
603 clog << " -> " << Access << ':' << QuoteString(Message.str(),"\n") << endl;
604 OutQueue += Message.str();
605 OutReady = true;
606
0a8a80e5
AL
607 return true;
608}
609 /*}}}*/
610// Worker::QueueItem - Add an item to the outbound queue /*{{{*/
611// ---------------------------------------------------------------------
612/* Send a URI Acquire message to the method */
613bool pkgAcquire::Worker::QueueItem(pkgAcquire::Queue::QItem *Item)
614{
615 if (OutFd == -1)
616 return false;
448c38bd 617
0a8a80e5
AL
618 string Message = "600 URI Acquire\n";
619 Message.reserve(300);
620 Message += "URI: " + Item->URI;
621 Message += "\nFilename: " + Item->Owner->DestFile;
08ea7806
DK
622
623 HashStringList const hsl = Item->GetExpectedHashes();
d003a557
DK
624 for (HashStringList::const_iterator hs = hsl.begin(); hs != hsl.end(); ++hs)
625 Message += "\nExpected-" + hs->HashType() + ": " + hs->HashValue();
08ea7806
DK
626
627 if (hsl.FileSize() == 0)
c48eea97 628 {
08ea7806
DK
629 unsigned long long FileSize = Item->GetMaximumSize();
630 if(FileSize > 0)
631 {
632 string MaximumSize;
633 strprintf(MaximumSize, "%llu", FileSize);
634 Message += "\nMaximum-Size: " + MaximumSize;
635 }
c48eea97 636 }
08ea7806
DK
637
638 Item->SyncDestinationFiles();
639 Message += Item->Custom600Headers();
0a8a80e5 640 Message += "\n\n";
359e1c4f
DK
641
642 if (RealFileExists(Item->Owner->DestFile))
643 {
514a25cb 644 std::string const SandboxUser = _config->Find("APT::Sandbox::User");
359e1c4f
DK
645 ChangeOwnerAndPermissionOfFile("Item::QueueURI", Item->Owner->DestFile.c_str(),
646 SandboxUser.c_str(), "root", 0600);
647 }
648
0a8a80e5
AL
649 if (Debug == true)
650 clog << " -> " << Access << ':' << QuoteString(Message,"\n") << endl;
651 OutQueue += Message;
652 OutReady = true;
448c38bd 653
0a8a80e5
AL
654 return true;
655}
656 /*}}}*/
657// Worker::OutFdRead - Out bound FD is ready /*{{{*/
658// ---------------------------------------------------------------------
659/* */
660bool pkgAcquire::Worker::OutFdReady()
661{
ee7af1bd
YY
662 int Res;
663 do
664 {
665 Res = write(OutFd,OutQueue.c_str(),OutQueue.length());
666 }
667 while (Res < 0 && errno == EINTR);
668
669 if (Res <= 0)
0a8a80e5 670 return MethodFailure();
ee7af1bd
YY
671
672 OutQueue.erase(0,Res);
0a8a80e5
AL
673 if (OutQueue.empty() == true)
674 OutReady = false;
448c38bd 675
0a8a80e5
AL
676 return true;
677}
678 /*}}}*/
679// Worker::InFdRead - In bound FD is ready /*{{{*/
680// ---------------------------------------------------------------------
681/* */
682bool pkgAcquire::Worker::InFdReady()
683{
684 if (ReadMessages() == false)
685 return false;
686 RunMessages();
687 return true;
688}
689 /*}}}*/
690// Worker::MethodFailure - Called when the method fails /*{{{*/
691// ---------------------------------------------------------------------
1e3f4083 692/* This is called when the method is believed to have failed, probably because
0a8a80e5
AL
693 read returned -1. */
694bool pkgAcquire::Worker::MethodFailure()
695{
76d97c26 696 _error->Error("Method %s has died unexpectedly!",Access.c_str());
448c38bd 697
ab7f4d7c
MV
698 // do not reap the child here to show meaningfull error to the user
699 ExecWait(Process,Access.c_str(),false);
0a8a80e5
AL
700 Process = -1;
701 close(InFd);
702 close(OutFd);
703 InFd = -1;
704 OutFd = -1;
705 OutReady = false;
706 InReady = false;
707 OutQueue = string();
708 MessageQueue.erase(MessageQueue.begin(),MessageQueue.end());
448c38bd 709
0a8a80e5
AL
710 return false;
711}
712 /*}}}*/
448c38bd 713// Worker::Pulse - Called periodically /*{{{*/
8267fe24
AL
714// ---------------------------------------------------------------------
715/* */
716void pkgAcquire::Worker::Pulse()
717{
718 if (CurrentItem == 0)
719 return;
448c38bd 720
8267fe24
AL
721 struct stat Buf;
722 if (stat(CurrentItem->Owner->DestFile.c_str(),&Buf) != 0)
723 return;
724 CurrentSize = Buf.st_size;
725}
726 /*}}}*/
727// Worker::ItemDone - Called when the current item is finished /*{{{*/
728// ---------------------------------------------------------------------
729/* */
730void pkgAcquire::Worker::ItemDone()
731{
732 CurrentItem = 0;
733 CurrentSize = 0;
734 TotalSize = 0;
735 Status = string();
736}
737 /*}}}*/
08ea7806
DK
738void pkgAcquire::Worker::PrepareFiles(char const * const caller, pkgAcquire::Queue::QItem const * const Itm)/*{{{*/
739{
740 if (RealFileExists(Itm->Owner->DestFile))
741 {
742 ChangeOwnerAndPermissionOfFile(caller, Itm->Owner->DestFile.c_str(), "root", "root", 0644);
743 std::string const filename = Itm->Owner->DestFile;
744 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
745 {
746 pkgAcquire::Item const * const Owner = *O;
ce1f3a2c 747 if (Owner->DestFile == filename || filename == "/dev/null")
08ea7806 748 continue;
ce1f3a2c 749 RemoveFile("PrepareFiles", Owner->DestFile);
08ea7806
DK
750 if (link(filename.c_str(), Owner->DestFile.c_str()) != 0)
751 {
3d8232bf 752 // different mounts can't happen for us as we download to lists/ by default,
08ea7806
DK
753 // but if the system is reused by others the locations can potentially be on
754 // different disks, so use symlink as poor-men replacement.
755 // FIXME: Real copying as last fallback, but that is costly, so offload to a method preferable
756 if (symlink(filename.c_str(), Owner->DestFile.c_str()) != 0)
757 _error->Error("Can't create (sym)link of file %s to %s", filename.c_str(), Owner->DestFile.c_str());
758 }
759 }
760 }
761 else
762 {
763 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
ce1f3a2c 764 RemoveFile("PrepareFiles", (*O)->DestFile);
08ea7806
DK
765 }
766}
767 /*}}}*/