]> git.saurik.com Git - apt.git/blame_incremental - apt-pkg/acquire-worker.cc
refactor EDSP classes for better internal reuse
[apt.git] / apt-pkg / acquire-worker.cc
... / ...
CommitLineData
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
3// $Id: acquire-worker.cc,v 1.34 2001/05/22 04:42:54 jgg Exp $
4/* ######################################################################
5
6 Acquire Worker
7
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
12 ##################################################################### */
13 /*}}}*/
14// Include Files /*{{{*/
15#include <config.h>
16
17#include <apt-pkg/acquire.h>
18#include <apt-pkg/acquire-worker.h>
19#include <apt-pkg/acquire-item.h>
20#include <apt-pkg/configuration.h>
21#include <apt-pkg/error.h>
22#include <apt-pkg/fileutl.h>
23#include <apt-pkg/strutl.h>
24#include <apt-pkg/hashes.h>
25
26#include <algorithm>
27#include <string>
28#include <vector>
29#include <iostream>
30
31#include <sys/stat.h>
32#include <stdlib.h>
33#include <unistd.h>
34#include <signal.h>
35#include <stdio.h>
36#include <errno.h>
37#include <sstream>
38
39#include <apti18n.h>
40 /*}}}*/
41
42using namespace std;
43
44// Worker::Worker - Constructor for Queue startup /*{{{*/
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)
48{
49 Construct();
50}
51 /*}}}*/
52// Worker::Worker - Constructor for method config startup /*{{{*/
53pkgAcquire::Worker::Worker(MethodConfig *Cnf) : Worker(nullptr, Cnf, nullptr)
54{
55}
56 /*}}}*/
57// Worker::Construct - Constructor helper /*{{{*/
58// ---------------------------------------------------------------------
59/* */
60void pkgAcquire::Worker::Construct()
61{
62 NextQueue = 0;
63 NextAcquire = 0;
64 Process = -1;
65 InFd = -1;
66 OutFd = -1;
67 OutReady = false;
68 InReady = false;
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)
81 {
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);
86 ExecWait(Process,Access.c_str(),true);
87 }
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)
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 }
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 }
117 for (int I = 0; I != 4; I++)
118 SetCloseExec(Pipes[I],true);
119
120 // Fork off the process
121 Process = ExecFork();
122 if (Process == 0)
123 {
124 // Setup the FDs
125 dup2(Pipes[1],STDOUT_FILENO);
126 dup2(Pipes[2],STDIN_FILENO);
127 SetCloseExec(STDOUT_FILENO,false);
128 SetCloseExec(STDIN_FILENO,false);
129 SetCloseExec(STDERR_FILENO,false);
130
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;
136 _exit(100);
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]);
146 OutReady = false;
147 InReady = true;
148
149 // Read the configuration data
150 if (WaitFd(InFd) == false ||
151 ReadMessages() == false)
152 return _error->Error(_("Method %s did not start correctly"),Method.c_str());
153
154 RunMessages();
155 if (OwnerQ != 0)
156 SendConfiguration();
157
158 return true;
159}
160 /*}}}*/
161// Worker::ReadMessages - Read all pending messages into the list /*{{{*/
162// ---------------------------------------------------------------------
163/* */
164bool pkgAcquire::Worker::ReadMessages()
165{
166 if (::ReadMessages(InFd,MessageQueue) == false)
167 return MethodFailure();
168 return true;
169}
170 /*}}}*/
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. */
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}
194bool pkgAcquire::Worker::RunMessages()
195{
196 while (MessageQueue.empty() == false)
197 {
198 string Message = MessageQueue.front();
199 MessageQueue.erase(MessageQueue.begin());
200
201 if (Debug == true)
202 clog << " <- " << Access << ':' << QuoteString(Message,"\n") << endl;
203
204 // Fetch the message number
205 char *End;
206 MessageType const Number = static_cast<MessageType>(strtoul(Message.c_str(),&End,10));
207 if (End == Message.c_str())
208 return _error->Error("Invalid message from method %s: %s",Access.c_str(),Message.c_str());
209
210 string URI = LookupTag(Message,"URI");
211 pkgAcquire::Queue::QItem *Itm = NULL;
212 if (URI.empty() == false)
213 Itm = OwnerQ->FindItem(URI,this);
214
215 if (Itm != NULL)
216 {
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 }
227 }
228
229 // Determine the message number and dispatch
230 switch (Number)
231 {
232 case MessageType::CAPABILITIES:
233 if (Capabilities(Message) == false)
234 return _error->Error("Unable to process Capabilities message from %s",Access.c_str());
235 break;
236
237 case MessageType::LOG:
238 if (Debug == true)
239 clog << " <- (log) " << LookupTag(Message,"Message") << endl;
240 break;
241
242 case MessageType::STATUS:
243 Status = LookupTag(Message,"Message");
244 break;
245
246 case MessageType::REDIRECT:
247 {
248 if (Itm == nullptr)
249 {
250 _error->Error("Method gave invalid 103 Redirect message");
251 break;
252 }
253
254 std::string const NewURI = LookupTag(Message,"New-URI",URI.c_str());
255 Itm->URI = NewURI;
256
257 ItemDone();
258
259 // Change the status so that it can be dequeued
260 for (auto const &O: Itm->Owners)
261 O->Status = pkgAcquire::Item::StatIdle;
262 // Mark the item as done (taking care of all queues)
263 // and then put it in the main queue again
264 std::vector<Item*> const ItmOwners = Itm->Owners;
265 OwnerQ->ItemDone(Itm);
266 Itm = nullptr;
267 for (auto const &Owner: ItmOwners)
268 {
269 pkgAcquire::ItemDesc &desc = Owner->GetItemDesc();
270 if (Log != nullptr)
271 Log->Done(desc);
272
273 // if we change site, treat it as a mirror change
274 if (URI::SiteOnly(NewURI) != URI::SiteOnly(desc.URI))
275 {
276 auto const firstSpace = desc.Description.find(" ");
277 if (firstSpace != std::string::npos)
278 {
279 std::string const OldSite = desc.Description.substr(0, firstSpace);
280 if (likely(APT::String::Startswith(desc.URI, OldSite)))
281 {
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 }
289 }
290 }
291 }
292 desc.URI = NewURI;
293 if (isDoomedItem(Owner) == false)
294 OwnerQ->Owner->Enqueue(desc);
295 }
296 break;
297 }
298
299 case MessageType::WARNING:
300 _error->Warning("%s: %s", Itm->Owner->DescURI().c_str(), LookupTag(Message,"Message").c_str());
301 break;
302
303 case MessageType::URI_START:
304 {
305 if (Itm == nullptr)
306 {
307 _error->Error("Method gave invalid 200 URI Start message");
308 break;
309 }
310
311 CurrentItem = Itm;
312 CurrentSize = 0;
313 TotalSize = strtoull(LookupTag(Message,"Size","0").c_str(), NULL, 10);
314 ResumePoint = strtoull(LookupTag(Message,"Resume-Point","0").c_str(), NULL, 10);
315 for (auto const Owner: Itm->Owners)
316 {
317 Owner->Start(Message, TotalSize);
318 // Display update before completion
319 if (Log != nullptr)
320 {
321 if (Log->MorePulses == true)
322 Log->Pulse(Owner->GetOwner());
323 Log->Fetch(Owner->GetItemDesc());
324 }
325 }
326
327 break;
328 }
329
330 case MessageType::URI_DONE:
331 {
332 if (Itm == nullptr)
333 {
334 _error->Error("Method gave invalid 201 URI Done message");
335 break;
336 }
337
338 PrepareFiles("201::URIDone", Itm);
339
340 // Display update before completion
341 if (Log != 0 && Log->MorePulses == true)
342 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
343 Log->Pulse((*O)->GetOwner());
344
345 HashStringList ReceivedHashes;
346 {
347 std::string const givenfilename = LookupTag(Message, "Filename");
348 std::string const filename = givenfilename.empty() ? Itm->Owner->DestFile : givenfilename;
349 // see if we got hashes to verify
350 for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
351 {
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 }
368 }
369
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 }
374
375 std::vector<Item*> const ItmOwners = Itm->Owners;
376 OwnerQ->ItemDone(Itm);
377 Itm = NULL;
378
379 bool const isIMSHit = StringToBool(LookupTag(Message,"IMS-Hit"),false) ||
380 StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false);
381 for (auto const Owner: ItmOwners)
382 {
383 HashStringList const ExpectedHashes = Owner->GetExpectedHashes();
384 if(_config->FindB("Debug::pkgAcquire::Auth", false) == true)
385 {
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;
394 }
395
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;
411
412 }
413 else if (Owner->HashesRequired() == true)
414 consideredOkay = false;
415 else
416 {
417 consideredOkay = true;
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 }
423
424 if (consideredOkay == true)
425 consideredOkay = Owner->VerifyDone(Message, Config);
426 else // hashsum mismatch
427 Owner->Status = pkgAcquire::Item::StatAuthError;
428
429
430 if (consideredOkay == true)
431 {
432 if (isDoomedItem(Owner) == false)
433 Owner->Done(Message, ReceivedHashes, Config);
434 if (Log != nullptr)
435 {
436 if (isIMSHit)
437 Log->IMSHit(Owner->GetItemDesc());
438 else
439 Log->Done(Owner->GetItemDesc());
440 }
441 }
442 else
443 {
444 if (isDoomedItem(Owner) == false)
445 {
446 Message.append("\nFailReason: HashSumMismatch");
447 Owner->Failed(Message,Config);
448 }
449 if (Log != nullptr)
450 Log->Fail(Owner->GetItemDesc());
451 }
452 }
453 ItemDone();
454 break;
455 }
456
457 case MessageType::URI_FAILURE:
458 {
459 if (Itm == nullptr)
460 {
461 std::string const msg = LookupTag(Message,"Message");
462 _error->Error("Method gave invalid 400 URI Failure message: %s", msg.c_str());
463 break;
464 }
465
466 PrepareFiles("400::URIFailure", Itm);
467
468 // Display update before completion
469 if (Log != nullptr && Log->MorePulses == true)
470 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
471 Log->Pulse((*O)->GetOwner());
472
473 std::vector<Item*> const ItmOwners = Itm->Owners;
474 OwnerQ->ItemDone(Itm);
475 Itm = nullptr;
476
477 bool errTransient = false, errAuthErr = false;
478 {
479 std::string const failReason = LookupTag(Message, "FailReason");
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 }
490 }
491
492 for (auto const Owner: ItmOwners)
493 {
494 if (errAuthErr && Owner->GetExpectedHashes().empty() == false)
495 Owner->Status = pkgAcquire::Item::StatAuthError;
496 else if (errTransient)
497 Owner->Status = pkgAcquire::Item::StatTransientNetworkError;
498
499 if (isDoomedItem(Owner) == false)
500 Owner->Failed(Message,Config);
501 if (Log != nullptr)
502 Log->Fail(Owner->GetItemDesc());
503 }
504 ItemDone();
505
506 break;
507 }
508
509 case MessageType::GENERAL_FAILURE:
510 _error->Error("Method %s General failure: %s",Access.c_str(),LookupTag(Message,"Message").c_str());
511 break;
512
513 case MessageType::MEDIA_CHANGE:
514 MediaChange(Message);
515 break;
516 }
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;
529
530 Config->Version = LookupTag(Message,"Version");
531 Config->SingleInstance = StringToBool(LookupTag(Message,"Single-Instance"),false);
532 Config->Pipeline = StringToBool(LookupTag(Message,"Pipeline"),false);
533 Config->SendConfig = StringToBool(LookupTag(Message,"Send-Config"),false);
534 Config->LocalOnly = StringToBool(LookupTag(Message,"Local-Only"),false);
535 Config->NeedsCleanup = StringToBool(LookupTag(Message,"Needs-Cleanup"),false);
536 Config->Removable = StringToBool(LookupTag(Message,"Removable"),false);
537
538 // Some debug text
539 if (Debug == true)
540 {
541 clog << "Configured access method " << Config->Access << endl;
542 clog << "Version:" << Config->Version <<
543 " SingleInstance:" << Config->SingleInstance <<
544 " Pipeline:" << Config->Pipeline <<
545 " SendConfig:" << Config->SendConfig <<
546 " LocalOnly: " << Config->LocalOnly <<
547 " NeedsCleanup: " << Config->NeedsCleanup <<
548 " Removable: " << Config->Removable << endl;
549 }
550
551 return true;
552}
553 /*}}}*/
554// Worker::MediaChange - Request a media change /*{{{*/
555// ---------------------------------------------------------------------
556/* */
557bool pkgAcquire::Worker::MediaChange(string Message)
558{
559 int status_fd = _config->FindI("APT::Status-Fd",-1);
560 if(status_fd > 0)
561 {
562 string Media = LookupTag(Message,"Media");
563 string Drive = LookupTag(Message,"Drive");
564 ostringstream msg,status;
565 ioprintf(msg,_("Please insert the disc labeled: "
566 "'%s' "
567 "in the drive '%s' and press [Enter]."),
568 Media.c_str(),Drive.c_str());
569 status << "media-change: " // message
570 << Media << ":" // media
571 << Drive << ":" // drive
572 << msg.str() // l10n message
573 << endl;
574
575 std::string const dlstatus = status.str();
576 FileFd::Write(status_fd, dlstatus.c_str(), dlstatus.size());
577 }
578
579 if (Log == 0 || Log->MediaChange(LookupTag(Message,"Media"),
580 LookupTag(Message,"Drive")) == false)
581 {
582 char S[300];
583 snprintf(S,sizeof(S),"603 Media Changed\nFailed: true\n\n");
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];
592 snprintf(S,sizeof(S),"603 Media Changed\n\n");
593 if (Debug == true)
594 clog << " -> " << Access << ':' << QuoteString(S,"\n") << endl;
595 OutQueue += S;
596 OutReady = true;
597 return true;
598}
599 /*}}}*/
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;
610
611 /* Write out all of the configuration directives by walking the
612 configuration tree */
613 std::ostringstream Message;
614 Message << "601 Configuration\n";
615 _config->Dump(Message, NULL, "Config-Item: %F=%V\n", false);
616 Message << '\n';
617
618 if (Debug == true)
619 clog << " -> " << Access << ':' << QuoteString(Message.str(),"\n") << endl;
620 OutQueue += Message.str();
621 OutReady = true;
622
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;
633
634 string Message = "600 URI Acquire\n";
635 Message.reserve(300);
636 Message += "URI: " + Item->URI;
637 Message += "\nFilename: " + Item->Owner->DestFile;
638
639 HashStringList const hsl = Item->GetExpectedHashes();
640 for (HashStringList::const_iterator hs = hsl.begin(); hs != hsl.end(); ++hs)
641 Message += "\nExpected-" + hs->HashType() + ": " + hs->HashValue();
642
643 if (hsl.FileSize() == 0)
644 {
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 }
652 }
653
654 Item->SyncDestinationFiles();
655 Message += Item->Custom600Headers();
656 Message += "\n\n";
657
658 if (RealFileExists(Item->Owner->DestFile))
659 {
660 std::string const SandboxUser = _config->Find("APT::Sandbox::User");
661 ChangeOwnerAndPermissionOfFile("Item::QueueURI", Item->Owner->DestFile.c_str(),
662 SandboxUser.c_str(), "root", 0600);
663 }
664
665 if (Debug == true)
666 clog << " -> " << Access << ':' << QuoteString(Message,"\n") << endl;
667 OutQueue += Message;
668 OutReady = true;
669
670 return true;
671}
672 /*}}}*/
673// Worker::OutFdRead - Out bound FD is ready /*{{{*/
674// ---------------------------------------------------------------------
675/* */
676bool pkgAcquire::Worker::OutFdReady()
677{
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)
686 return MethodFailure();
687
688 OutQueue.erase(0,Res);
689 if (OutQueue.empty() == true)
690 OutReady = false;
691
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// ---------------------------------------------------------------------
708/* This is called when the method is believed to have failed, probably because
709 read returned -1. */
710bool pkgAcquire::Worker::MethodFailure()
711{
712 _error->Error("Method %s has died unexpectedly!",Access.c_str());
713
714 // do not reap the child here to show meaningfull error to the user
715 ExecWait(Process,Access.c_str(),false);
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());
725
726 return false;
727}
728 /*}}}*/
729// Worker::Pulse - Called periodically /*{{{*/
730// ---------------------------------------------------------------------
731/* */
732void pkgAcquire::Worker::Pulse()
733{
734 if (CurrentItem == 0)
735 return;
736
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 /*}}}*/
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;
763 if (Owner->DestFile == filename || filename == "/dev/null")
764 continue;
765 RemoveFile("PrepareFiles", Owner->DestFile);
766 if (link(filename.c_str(), Owner->DestFile.c_str()) != 0)
767 {
768 // different mounts can't happen for us as we download to lists/ by default,
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)
780 RemoveFile("PrepareFiles", (*O)->DestFile);
781 }
782}
783 /*}}}*/