]> git.saurik.com Git - apt.git/blame_incremental - apt-pkg/acquire-worker.cc
stop handling items in doomed transactions
[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 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 }
289 desc.URI = NewURI;
290 if (isDoomedItem(Owner) == false)
291 OwnerQ->Owner->Enqueue(desc);
292 }
293 break;
294 }
295
296 case MessageType::WARNING:
297 _error->Warning("%s: %s", Itm->Owner->DescURI().c_str(), LookupTag(Message,"Message").c_str());
298 break;
299
300 case MessageType::URI_START:
301 {
302 if (Itm == nullptr)
303 {
304 _error->Error("Method gave invalid 200 URI Start message");
305 break;
306 }
307
308 CurrentItem = Itm;
309 CurrentSize = 0;
310 TotalSize = strtoull(LookupTag(Message,"Size","0").c_str(), NULL, 10);
311 ResumePoint = strtoull(LookupTag(Message,"Resume-Point","0").c_str(), NULL, 10);
312 for (auto const Owner: Itm->Owners)
313 {
314 Owner->Start(Message, TotalSize);
315 // Display update before completion
316 if (Log != nullptr)
317 {
318 if (Log->MorePulses == true)
319 Log->Pulse(Owner->GetOwner());
320 Log->Fetch(Owner->GetItemDesc());
321 }
322 }
323
324 break;
325 }
326
327 case MessageType::URI_DONE:
328 {
329 if (Itm == nullptr)
330 {
331 _error->Error("Method gave invalid 201 URI Done message");
332 break;
333 }
334
335 PrepareFiles("201::URIDone", Itm);
336
337 // Display update before completion
338 if (Log != 0 && Log->MorePulses == true)
339 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
340 Log->Pulse((*O)->GetOwner());
341
342 HashStringList ReceivedHashes;
343 {
344 std::string const givenfilename = LookupTag(Message, "Filename");
345 std::string const filename = givenfilename.empty() ? Itm->Owner->DestFile : givenfilename;
346 // see if we got hashes to verify
347 for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
348 {
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 }
365 }
366
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 }
371
372 std::vector<Item*> const ItmOwners = Itm->Owners;
373 OwnerQ->ItemDone(Itm);
374 Itm = NULL;
375
376 bool const isIMSHit = StringToBool(LookupTag(Message,"IMS-Hit"),false) ||
377 StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false);
378 for (auto const Owner: ItmOwners)
379 {
380 HashStringList const ExpectedHashes = Owner->GetExpectedHashes();
381 if(_config->FindB("Debug::pkgAcquire::Auth", false) == true)
382 {
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;
391 }
392
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;
408
409 }
410 else if (Owner->HashesRequired() == true)
411 consideredOkay = false;
412 else
413 {
414 consideredOkay = true;
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 }
420
421 if (consideredOkay == true)
422 consideredOkay = Owner->VerifyDone(Message, Config);
423 else // hashsum mismatch
424 Owner->Status = pkgAcquire::Item::StatAuthError;
425
426
427 if (consideredOkay == true)
428 {
429 if (isDoomedItem(Owner) == false)
430 Owner->Done(Message, ReceivedHashes, Config);
431 if (Log != nullptr)
432 {
433 if (isIMSHit)
434 Log->IMSHit(Owner->GetItemDesc());
435 else
436 Log->Done(Owner->GetItemDesc());
437 }
438 }
439 else
440 {
441 if (isDoomedItem(Owner) == false)
442 Owner->Failed(Message,Config);
443 if (Log != nullptr)
444 Log->Fail(Owner->GetItemDesc());
445 }
446 }
447 ItemDone();
448 break;
449 }
450
451 case MessageType::URI_FAILURE:
452 {
453 if (Itm == nullptr)
454 {
455 std::string const msg = LookupTag(Message,"Message");
456 _error->Error("Method gave invalid 400 URI Failure message: %s", msg.c_str());
457 break;
458 }
459
460 PrepareFiles("400::URIFailure", Itm);
461
462 // Display update before completion
463 if (Log != nullptr && Log->MorePulses == true)
464 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
465 Log->Pulse((*O)->GetOwner());
466
467 std::vector<Item*> const ItmOwners = Itm->Owners;
468 OwnerQ->ItemDone(Itm);
469 Itm = nullptr;
470
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
479 for (auto const Owner: ItmOwners)
480 {
481 if (errTransient)
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());
487 }
488 ItemDone();
489
490 break;
491 }
492
493 case MessageType::GENERAL_FAILURE:
494 _error->Error("Method %s General failure: %s",Access.c_str(),LookupTag(Message,"Message").c_str());
495 break;
496
497 case MessageType::MEDIA_CHANGE:
498 MediaChange(Message);
499 break;
500 }
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;
513
514 Config->Version = LookupTag(Message,"Version");
515 Config->SingleInstance = StringToBool(LookupTag(Message,"Single-Instance"),false);
516 Config->Pipeline = StringToBool(LookupTag(Message,"Pipeline"),false);
517 Config->SendConfig = StringToBool(LookupTag(Message,"Send-Config"),false);
518 Config->LocalOnly = StringToBool(LookupTag(Message,"Local-Only"),false);
519 Config->NeedsCleanup = StringToBool(LookupTag(Message,"Needs-Cleanup"),false);
520 Config->Removable = StringToBool(LookupTag(Message,"Removable"),false);
521
522 // Some debug text
523 if (Debug == true)
524 {
525 clog << "Configured access method " << Config->Access << endl;
526 clog << "Version:" << Config->Version <<
527 " SingleInstance:" << Config->SingleInstance <<
528 " Pipeline:" << Config->Pipeline <<
529 " SendConfig:" << Config->SendConfig <<
530 " LocalOnly: " << Config->LocalOnly <<
531 " NeedsCleanup: " << Config->NeedsCleanup <<
532 " Removable: " << Config->Removable << endl;
533 }
534
535 return true;
536}
537 /*}}}*/
538// Worker::MediaChange - Request a media change /*{{{*/
539// ---------------------------------------------------------------------
540/* */
541bool pkgAcquire::Worker::MediaChange(string Message)
542{
543 int status_fd = _config->FindI("APT::Status-Fd",-1);
544 if(status_fd > 0)
545 {
546 string Media = LookupTag(Message,"Media");
547 string Drive = LookupTag(Message,"Drive");
548 ostringstream msg,status;
549 ioprintf(msg,_("Please insert the disc labeled: "
550 "'%s' "
551 "in the drive '%s' and press [Enter]."),
552 Media.c_str(),Drive.c_str());
553 status << "media-change: " // message
554 << Media << ":" // media
555 << Drive << ":" // drive
556 << msg.str() // l10n message
557 << endl;
558
559 std::string const dlstatus = status.str();
560 FileFd::Write(status_fd, dlstatus.c_str(), dlstatus.size());
561 }
562
563 if (Log == 0 || Log->MediaChange(LookupTag(Message,"Media"),
564 LookupTag(Message,"Drive")) == false)
565 {
566 char S[300];
567 snprintf(S,sizeof(S),"603 Media Changed\nFailed: true\n\n");
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];
576 snprintf(S,sizeof(S),"603 Media Changed\n\n");
577 if (Debug == true)
578 clog << " -> " << Access << ':' << QuoteString(S,"\n") << endl;
579 OutQueue += S;
580 OutReady = true;
581 return true;
582}
583 /*}}}*/
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;
594
595 /* Write out all of the configuration directives by walking the
596 configuration tree */
597 std::ostringstream Message;
598 Message << "601 Configuration\n";
599 _config->Dump(Message, NULL, "Config-Item: %F=%V\n", false);
600 Message << '\n';
601
602 if (Debug == true)
603 clog << " -> " << Access << ':' << QuoteString(Message.str(),"\n") << endl;
604 OutQueue += Message.str();
605 OutReady = true;
606
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;
617
618 string Message = "600 URI Acquire\n";
619 Message.reserve(300);
620 Message += "URI: " + Item->URI;
621 Message += "\nFilename: " + Item->Owner->DestFile;
622
623 HashStringList const hsl = Item->GetExpectedHashes();
624 for (HashStringList::const_iterator hs = hsl.begin(); hs != hsl.end(); ++hs)
625 Message += "\nExpected-" + hs->HashType() + ": " + hs->HashValue();
626
627 if (hsl.FileSize() == 0)
628 {
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 }
636 }
637
638 Item->SyncDestinationFiles();
639 Message += Item->Custom600Headers();
640 Message += "\n\n";
641
642 if (RealFileExists(Item->Owner->DestFile))
643 {
644 std::string const SandboxUser = _config->Find("APT::Sandbox::User");
645 ChangeOwnerAndPermissionOfFile("Item::QueueURI", Item->Owner->DestFile.c_str(),
646 SandboxUser.c_str(), "root", 0600);
647 }
648
649 if (Debug == true)
650 clog << " -> " << Access << ':' << QuoteString(Message,"\n") << endl;
651 OutQueue += Message;
652 OutReady = true;
653
654 return true;
655}
656 /*}}}*/
657// Worker::OutFdRead - Out bound FD is ready /*{{{*/
658// ---------------------------------------------------------------------
659/* */
660bool pkgAcquire::Worker::OutFdReady()
661{
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)
670 return MethodFailure();
671
672 OutQueue.erase(0,Res);
673 if (OutQueue.empty() == true)
674 OutReady = false;
675
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// ---------------------------------------------------------------------
692/* This is called when the method is believed to have failed, probably because
693 read returned -1. */
694bool pkgAcquire::Worker::MethodFailure()
695{
696 _error->Error("Method %s has died unexpectedly!",Access.c_str());
697
698 // do not reap the child here to show meaningfull error to the user
699 ExecWait(Process,Access.c_str(),false);
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());
709
710 return false;
711}
712 /*}}}*/
713// Worker::Pulse - Called periodically /*{{{*/
714// ---------------------------------------------------------------------
715/* */
716void pkgAcquire::Worker::Pulse()
717{
718 if (CurrentItem == 0)
719 return;
720
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 /*}}}*/
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;
747 if (Owner->DestFile == filename || filename == "/dev/null")
748 continue;
749 RemoveFile("PrepareFiles", Owner->DestFile);
750 if (link(filename.c_str(), Owner->DestFile.c_str()) != 0)
751 {
752 // different mounts can't happen for us as we download to lists/ by default,
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)
764 RemoveFile("PrepareFiles", (*O)->DestFile);
765 }
766}
767 /*}}}*/