]> git.saurik.com Git - apt.git/blame - apt-pkg/acquire-worker.cc
refactor EDSP classes for better internal reuse
[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);
38f8704e 381 for (auto const Owner: ItmOwners)
8267fe24 382 {
08ea7806
DK
383 HashStringList const ExpectedHashes = Owner->GetExpectedHashes();
384 if(_config->FindB("Debug::pkgAcquire::Auth", false) == true)
c46824ce 385 {
08ea7806
DK
386 std::clog << "201 URI Done: " << Owner->DescURI() << endl
387 << "ReceivedHash:" << endl;
388 for (HashStringList::const_iterator hs = ReceivedHashes.begin(); hs != ReceivedHashes.end(); ++hs)
389 std::clog << "\t- " << hs->toStr() << std::endl;
390 std::clog << "ExpectedHash:" << endl;
391 for (HashStringList::const_iterator hs = ExpectedHashes.begin(); hs != ExpectedHashes.end(); ++hs)
392 std::clog << "\t- " << hs->toStr() << std::endl;
393 std::clog << endl;
448c38bd 394 }
448c38bd 395
08ea7806
DK
396 // decide if what we got is what we expected
397 bool consideredOkay = false;
398 if (ExpectedHashes.usable())
399 {
400 if (ReceivedHashes.usable() == false)
401 {
402 /* IMS-Hits can't be checked here as we will have uncompressed file,
403 but the hashes for the compressed file. What we have was good through
404 so all we have to ensure later is that we are not stalled. */
405 consideredOkay = isIMSHit;
406 }
407 else if (ReceivedHashes == ExpectedHashes)
408 consideredOkay = true;
409 else
410 consideredOkay = false;
448c38bd 411
08ea7806
DK
412 }
413 else if (Owner->HashesRequired() == true)
414 consideredOkay = false;
415 else
63d60998 416 {
08ea7806 417 consideredOkay = true;
63d60998
DK
418 // even if the hashes aren't usable to declare something secure
419 // we can at least use them to declare it an integrity failure
420 if (ExpectedHashes.empty() == false && ReceivedHashes != ExpectedHashes && _config->Find("Acquire::ForceHash").empty())
421 consideredOkay = false;
422 }
448c38bd 423
dd676dc7
DK
424 if (consideredOkay == true)
425 consideredOkay = Owner->VerifyDone(Message, Config);
426 else // hashsum mismatch
427 Owner->Status = pkgAcquire::Item::StatAuthError;
428
38f8704e 429
08ea7806 430 if (consideredOkay == true)
448c38bd 431 {
38f8704e
DK
432 if (isDoomedItem(Owner) == false)
433 Owner->Done(Message, ReceivedHashes, Config);
434 if (Log != nullptr)
448c38bd 435 {
08ea7806
DK
436 if (isIMSHit)
437 Log->IMSHit(Owner->GetItemDesc());
438 else
439 Log->Done(Owner->GetItemDesc());
448c38bd 440 }
448c38bd 441 }
08ea7806
DK
442 else
443 {
38f8704e 444 if (isDoomedItem(Owner) == false)
0340069c
DK
445 {
446 Message.append("\nFailReason: HashSumMismatch");
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 {
487 auto const reasons = { "HashSumMismatch", "MaximumSizeExceeded" };
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
0a8a80e5
AL
634 string Message = "600 URI Acquire\n";
635 Message.reserve(300);
636 Message += "URI: " + Item->URI;
637 Message += "\nFilename: " + Item->Owner->DestFile;
08ea7806
DK
638
639 HashStringList const hsl = Item->GetExpectedHashes();
d003a557
DK
640 for (HashStringList::const_iterator hs = hsl.begin(); hs != hsl.end(); ++hs)
641 Message += "\nExpected-" + hs->HashType() + ": " + hs->HashValue();
08ea7806
DK
642
643 if (hsl.FileSize() == 0)
c48eea97 644 {
08ea7806
DK
645 unsigned long long FileSize = Item->GetMaximumSize();
646 if(FileSize > 0)
647 {
648 string MaximumSize;
649 strprintf(MaximumSize, "%llu", FileSize);
650 Message += "\nMaximum-Size: " + MaximumSize;
651 }
c48eea97 652 }
08ea7806
DK
653
654 Item->SyncDestinationFiles();
655 Message += Item->Custom600Headers();
0a8a80e5 656 Message += "\n\n";
359e1c4f
DK
657
658 if (RealFileExists(Item->Owner->DestFile))
659 {
514a25cb 660 std::string const SandboxUser = _config->Find("APT::Sandbox::User");
359e1c4f
DK
661 ChangeOwnerAndPermissionOfFile("Item::QueueURI", Item->Owner->DestFile.c_str(),
662 SandboxUser.c_str(), "root", 0600);
663 }
664
0a8a80e5
AL
665 if (Debug == true)
666 clog << " -> " << Access << ':' << QuoteString(Message,"\n") << endl;
667 OutQueue += Message;
668 OutReady = true;
448c38bd 669
0a8a80e5
AL
670 return true;
671}
672 /*}}}*/
673// Worker::OutFdRead - Out bound FD is ready /*{{{*/
674// ---------------------------------------------------------------------
675/* */
676bool pkgAcquire::Worker::OutFdReady()
677{
ee7af1bd
YY
678 int Res;
679 do
680 {
681 Res = write(OutFd,OutQueue.c_str(),OutQueue.length());
682 }
683 while (Res < 0 && errno == EINTR);
684
685 if (Res <= 0)
0a8a80e5 686 return MethodFailure();
ee7af1bd
YY
687
688 OutQueue.erase(0,Res);
0a8a80e5
AL
689 if (OutQueue.empty() == true)
690 OutReady = false;
448c38bd 691
0a8a80e5
AL
692 return true;
693}
694 /*}}}*/
695// Worker::InFdRead - In bound FD is ready /*{{{*/
696// ---------------------------------------------------------------------
697/* */
698bool pkgAcquire::Worker::InFdReady()
699{
700 if (ReadMessages() == false)
701 return false;
702 RunMessages();
703 return true;
704}
705 /*}}}*/
706// Worker::MethodFailure - Called when the method fails /*{{{*/
707// ---------------------------------------------------------------------
1e3f4083 708/* This is called when the method is believed to have failed, probably because
0a8a80e5
AL
709 read returned -1. */
710bool pkgAcquire::Worker::MethodFailure()
711{
76d97c26 712 _error->Error("Method %s has died unexpectedly!",Access.c_str());
448c38bd 713
ab7f4d7c
MV
714 // do not reap the child here to show meaningfull error to the user
715 ExecWait(Process,Access.c_str(),false);
0a8a80e5
AL
716 Process = -1;
717 close(InFd);
718 close(OutFd);
719 InFd = -1;
720 OutFd = -1;
721 OutReady = false;
722 InReady = false;
723 OutQueue = string();
724 MessageQueue.erase(MessageQueue.begin(),MessageQueue.end());
448c38bd 725
0a8a80e5
AL
726 return false;
727}
728 /*}}}*/
448c38bd 729// Worker::Pulse - Called periodically /*{{{*/
8267fe24
AL
730// ---------------------------------------------------------------------
731/* */
732void pkgAcquire::Worker::Pulse()
733{
734 if (CurrentItem == 0)
735 return;
448c38bd 736
8267fe24
AL
737 struct stat Buf;
738 if (stat(CurrentItem->Owner->DestFile.c_str(),&Buf) != 0)
739 return;
740 CurrentSize = Buf.st_size;
741}
742 /*}}}*/
743// Worker::ItemDone - Called when the current item is finished /*{{{*/
744// ---------------------------------------------------------------------
745/* */
746void pkgAcquire::Worker::ItemDone()
747{
748 CurrentItem = 0;
749 CurrentSize = 0;
750 TotalSize = 0;
751 Status = string();
752}
753 /*}}}*/
08ea7806
DK
754void pkgAcquire::Worker::PrepareFiles(char const * const caller, pkgAcquire::Queue::QItem const * const Itm)/*{{{*/
755{
756 if (RealFileExists(Itm->Owner->DestFile))
757 {
758 ChangeOwnerAndPermissionOfFile(caller, Itm->Owner->DestFile.c_str(), "root", "root", 0644);
759 std::string const filename = Itm->Owner->DestFile;
760 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
761 {
762 pkgAcquire::Item const * const Owner = *O;
ce1f3a2c 763 if (Owner->DestFile == filename || filename == "/dev/null")
08ea7806 764 continue;
ce1f3a2c 765 RemoveFile("PrepareFiles", Owner->DestFile);
08ea7806
DK
766 if (link(filename.c_str(), Owner->DestFile.c_str()) != 0)
767 {
3d8232bf 768 // different mounts can't happen for us as we download to lists/ by default,
08ea7806
DK
769 // but if the system is reused by others the locations can potentially be on
770 // different disks, so use symlink as poor-men replacement.
771 // FIXME: Real copying as last fallback, but that is costly, so offload to a method preferable
772 if (symlink(filename.c_str(), Owner->DestFile.c_str()) != 0)
773 _error->Error("Can't create (sym)link of file %s to %s", filename.c_str(), Owner->DestFile.c_str());
774 }
775 }
776 }
777 else
778 {
779 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
ce1f3a2c 780 RemoveFile("PrepareFiles", (*O)->DestFile);
08ea7806
DK
781 }
782}
783 /*}}}*/