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