]> git.saurik.com Git - apt.git/blame - apt-pkg/acquire-worker.cc
pkgPolicy: Introduce storage and helpers for per-version pins
[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
453b82a3
DK
26#include <string>
27#include <vector>
24a0d63a 28#include <iostream>
80a26ed1 29#include <sstream>
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>
359e1c4f
DK
37#include <sys/types.h>
38#include <pwd.h>
39#include <grp.h>
ea542140
DK
40
41#include <apti18n.h>
3b5421b4
AL
42 /*}}}*/
43
24a0d63a
AL
44using namespace std;
45
3b5421b4
AL
46// Worker::Worker - Constructor for Queue startup /*{{{*/
47// ---------------------------------------------------------------------
48/* */
8267fe24
AL
49pkgAcquire::Worker::Worker(Queue *Q,MethodConfig *Cnf,
50 pkgAcquireStatus *Log) : Log(Log)
3b5421b4
AL
51{
52 OwnerQ = Q;
0a8a80e5
AL
53 Config = Cnf;
54 Access = Cnf->Access;
55 CurrentItem = 0;
18ef0a78
AL
56 TotalSize = 0;
57 CurrentSize = 0;
448c38bd
DK
58
59 Construct();
3b5421b4
AL
60}
61 /*}}}*/
62// Worker::Worker - Constructor for method config startup /*{{{*/
63// ---------------------------------------------------------------------
64/* */
65pkgAcquire::Worker::Worker(MethodConfig *Cnf)
66{
67 OwnerQ = 0;
68 Config = Cnf;
69 Access = Cnf->Access;
0a8a80e5 70 CurrentItem = 0;
18ef0a78
AL
71 TotalSize = 0;
72 CurrentSize = 0;
448c38bd
DK
73
74 Construct();
3b5421b4
AL
75}
76 /*}}}*/
77// Worker::Construct - Constructor helper /*{{{*/
78// ---------------------------------------------------------------------
79/* */
80void pkgAcquire::Worker::Construct()
81{
0a8a80e5
AL
82 NextQueue = 0;
83 NextAcquire = 0;
3b5421b4
AL
84 Process = -1;
85 InFd = -1;
86 OutFd = -1;
0a8a80e5
AL
87 OutReady = false;
88 InReady = false;
3b5421b4
AL
89 Debug = _config->FindB("Debug::pkgAcquire::Worker",false);
90}
91 /*}}}*/
92// Worker::~Worker - Destructor /*{{{*/
93// ---------------------------------------------------------------------
94/* */
95pkgAcquire::Worker::~Worker()
96{
97 close(InFd);
98 close(OutFd);
99
100 if (Process > 0)
0a8a80e5 101 {
8e5fc8f5
AL
102 /* Closing of stdin is the signal to exit and die when the process
103 indicates it needs cleanup */
104 if (Config->NeedsCleanup == false)
105 kill(Process,SIGINT);
ddc1d8d0 106 ExecWait(Process,Access.c_str(),true);
0a8a80e5 107 }
3b5421b4
AL
108}
109 /*}}}*/
110// Worker::Start - Start the worker process /*{{{*/
111// ---------------------------------------------------------------------
112/* This forks the method and inits the communication channel */
113bool pkgAcquire::Worker::Start()
114{
115 // Get the method path
116 string Method = _config->FindDir("Dir::Bin::Methods") + Access;
117 if (FileExists(Method) == false)
9082a1fc
DK
118 {
119 _error->Error(_("The method driver %s could not be found."),Method.c_str());
120 if (Access == "https")
121 _error->Notice(_("Is the package %s installed?"), "apt-transport-https");
122 return false;
123 }
3b5421b4
AL
124
125 if (Debug == true)
126 clog << "Starting method '" << Method << '\'' << endl;
127
128 // Create the pipes
129 int Pipes[4] = {-1,-1,-1,-1};
130 if (pipe(Pipes) != 0 || pipe(Pipes+2) != 0)
131 {
132 _error->Errno("pipe","Failed to create IPC pipe to subprocess");
133 for (int I = 0; I != 4; I++)
134 close(Pipes[I]);
135 return false;
136 }
8b89e57f 137 for (int I = 0; I != 4; I++)
4490f2de 138 SetCloseExec(Pipes[I],true);
448c38bd 139
3b5421b4 140 // Fork off the process
54676e1a 141 Process = ExecFork();
3b5421b4
AL
142 if (Process == 0)
143 {
144 // Setup the FDs
145 dup2(Pipes[1],STDOUT_FILENO);
146 dup2(Pipes[2],STDIN_FILENO);
3b5421b4 147 SetCloseExec(STDOUT_FILENO,false);
448c38bd 148 SetCloseExec(STDIN_FILENO,false);
3b5421b4 149 SetCloseExec(STDERR_FILENO,false);
448c38bd 150
3b5421b4
AL
151 const char *Args[2];
152 Args[0] = Method.c_str();
153 Args[1] = 0;
154 execv(Args[0],(char **)Args);
155 cerr << "Failed to exec method " << Args[0] << endl;
0dbb95d8 156 _exit(100);
3b5421b4
AL
157 }
158
159 // Fix up our FDs
160 InFd = Pipes[0];
161 OutFd = Pipes[3];
162 SetNonBlock(Pipes[0],true);
163 SetNonBlock(Pipes[3],true);
164 close(Pipes[1]);
165 close(Pipes[2]);
0a8a80e5
AL
166 OutReady = false;
167 InReady = true;
448c38bd 168
3b5421b4
AL
169 // Read the configuration data
170 if (WaitFd(InFd) == false ||
171 ReadMessages() == false)
b2e465d6 172 return _error->Error(_("Method %s did not start correctly"),Method.c_str());
3b5421b4
AL
173
174 RunMessages();
8b89e57f
AL
175 if (OwnerQ != 0)
176 SendConfiguration();
448c38bd 177
3b5421b4
AL
178 return true;
179}
180 /*}}}*/
181// Worker::ReadMessages - Read all pending messages into the list /*{{{*/
182// ---------------------------------------------------------------------
0a8a80e5 183/* */
3b5421b4
AL
184bool pkgAcquire::Worker::ReadMessages()
185{
0a8a80e5
AL
186 if (::ReadMessages(InFd,MessageQueue) == false)
187 return MethodFailure();
3b5421b4
AL
188 return true;
189}
190 /*}}}*/
3b5421b4
AL
191// Worker::RunMessage - Empty the message queue /*{{{*/
192// ---------------------------------------------------------------------
193/* This takes the messages from the message queue and runs them through
194 the parsers in order. */
195bool pkgAcquire::Worker::RunMessages()
196{
197 while (MessageQueue.empty() == false)
198 {
199 string Message = MessageQueue.front();
200 MessageQueue.erase(MessageQueue.begin());
0a8a80e5
AL
201
202 if (Debug == true)
203 clog << " <- " << Access << ':' << QuoteString(Message,"\n") << endl;
448c38bd 204
3b5421b4
AL
205 // Fetch the message number
206 char *End;
207 int Number = strtol(Message.c_str(),&End,10);
208 if (End == Message.c_str())
209 return _error->Error("Invalid message from method %s: %s",Access.c_str(),Message.c_str());
210
c88edf1d
AL
211 string URI = LookupTag(Message,"URI");
212 pkgAcquire::Queue::QItem *Itm = 0;
213 if (URI.empty() == false)
214 Itm = OwnerQ->FindItem(URI,this);
196fd136
MV
215
216 // update used mirror
217 string UsedMirror = LookupTag(Message,"UsedMirror", "");
448c38bd 218 if (!UsedMirror.empty() &&
196fd136 219 Itm &&
448c38bd 220 Itm->Description.find(" ") != string::npos)
196fd136
MV
221 {
222 Itm->Description.replace(0, Itm->Description.find(" "), UsedMirror);
223 // FIXME: will we need this as well?
224 //Itm->ShortDesc = UsedMirror;
225 }
448c38bd 226
3b5421b4
AL
227 // Determine the message number and dispatch
228 switch (Number)
229 {
0a8a80e5 230 // 100 Capabilities
3b5421b4
AL
231 case 100:
232 if (Capabilities(Message) == false)
233 return _error->Error("Unable to process Capabilities message from %s",Access.c_str());
234 break;
448c38bd 235
0a8a80e5
AL
236 // 101 Log
237 case 101:
238 if (Debug == true)
239 clog << " <- (log) " << LookupTag(Message,"Message") << endl;
240 break;
448c38bd 241
0a8a80e5
AL
242 // 102 Status
243 case 102:
244 Status = LookupTag(Message,"Message");
245 break;
448c38bd 246
15d7e515
MV
247 // 103 Redirect
248 case 103:
249 {
250 if (Itm == 0)
251 {
252 _error->Error("Method gave invalid 103 Redirect message");
253 break;
254 }
448c38bd 255
15d7e515
MV
256 string NewURI = LookupTag(Message,"New-URI",URI.c_str());
257 Itm->URI = NewURI;
5674f6b3
RG
258
259 ItemDone();
260
5674f6b3 261 // Change the status so that it can be dequeued
08ea7806
DK
262 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
263 {
264 pkgAcquire::Item *Owner = *O;
265 Owner->Status = pkgAcquire::Item::StatIdle;
266 }
5674f6b3
RG
267 // Mark the item as done (taking care of all queues)
268 // and then put it in the main queue again
08ea7806 269 std::vector<Item*> const ItmOwners = Itm->Owners;
5674f6b3 270 OwnerQ->ItemDone(Itm);
08ea7806
DK
271 Itm = NULL;
272 for (pkgAcquire::Queue::QItem::owner_iterator O = ItmOwners.begin(); O != ItmOwners.end(); ++O)
273 {
274 pkgAcquire::Item *Owner = *O;
275 pkgAcquire::ItemDesc desc = Owner->GetItemDesc();
276 desc.URI = NewURI;
277 OwnerQ->Owner->Enqueue(desc);
5674f6b3 278
08ea7806
DK
279 if (Log != 0)
280 Log->Done(Owner->GetItemDesc());
281 }
15d7e515
MV
282 break;
283 }
448c38bd 284
0a8a80e5
AL
285 // 200 URI Start
286 case 200:
c88edf1d
AL
287 {
288 if (Itm == 0)
289 {
93bf083d 290 _error->Error("Method gave invalid 200 URI Start message");
c88edf1d
AL
291 break;
292 }
448c38bd 293
c88edf1d
AL
294 CurrentItem = Itm;
295 CurrentSize = 0;
650faab0
DK
296 TotalSize = strtoull(LookupTag(Message,"Size","0").c_str(), NULL, 10);
297 ResumePoint = strtoull(LookupTag(Message,"Resume-Point","0").c_str(), NULL, 10);
08ea7806
DK
298 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
299 {
300 (*O)->Start(Message, TotalSize);
448c38bd 301
08ea7806
DK
302 // Display update before completion
303 if (Log != 0)
304 {
305 if (Log->MorePulses == true)
306 Log->Pulse((*O)->GetOwner());
307 Log->Fetch((*O)->GetItemDesc());
308 }
309 }
8267fe24 310
c88edf1d
AL
311 break;
312 }
448c38bd 313
0a8a80e5
AL
314 // 201 URI Done
315 case 201:
c88edf1d
AL
316 {
317 if (Itm == 0)
318 {
93bf083d 319 _error->Error("Method gave invalid 201 URI Done message");
c88edf1d
AL
320 break;
321 }
448c38bd 322
08ea7806 323 PrepareFiles("201::URIDone", Itm);
359e1c4f 324
c5ccf175
AL
325 // Display update before completion
326 if (Log != 0 && Log->MorePulses == true)
08ea7806
DK
327 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
328 Log->Pulse((*O)->GetOwner());
448c38bd 329
08ea7806 330 std::string const filename = LookupTag(Message, "Filename", Itm->Owner->DestFile.c_str());
20801f61 331 HashStringList ReceivedHashes;
8a8feb29 332 {
08ea7806
DK
333 // see if we got hashes to verify
334 for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
448c38bd 335 {
08ea7806
DK
336 std::string const tagname = std::string(*type) + "-Hash";
337 std::string const hashsum = LookupTag(Message, tagname.c_str());
338 if (hashsum.empty() == false)
339 ReceivedHashes.push_back(HashString(*type, hashsum));
340 }
341 // not all methods always sent Hashes our way
342 if (ReceivedHashes.usable() == false)
343 {
344 HashStringList const ExpectedHashes = Itm->GetExpectedHashes();
345 if (ExpectedHashes.usable() == true && RealFileExists(filename))
346 {
347 Hashes calc(ExpectedHashes);
348 FileFd file(filename, FileFd::ReadOnly, FileFd::None);
349 calc.AddFD(file);
350 ReceivedHashes = calc.GetHashStringList();
351 }
448c38bd
DK
352 }
353 }
b3501edb 354
08ea7806
DK
355 // only local files can refer other filenames and counting them as fetched would be unfair
356 if (Log != NULL && filename != Itm->Owner->DestFile)
357 Log->Fetched(ReceivedHashes.FileSize(),atoi(LookupTag(Message,"Resume-Point","0").c_str()));
358
359 std::vector<Item*> const ItmOwners = Itm->Owners;
360 OwnerQ->ItemDone(Itm);
361 Itm = NULL;
b3501edb 362
448c38bd
DK
363 bool const isIMSHit = StringToBool(LookupTag(Message,"IMS-Hit"),false) ||
364 StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false);
08ea7806 365 for (pkgAcquire::Queue::QItem::owner_iterator O = ItmOwners.begin(); O != ItmOwners.end(); ++O)
8267fe24 366 {
08ea7806
DK
367 pkgAcquire::Item * const Owner = *O;
368 HashStringList const ExpectedHashes = Owner->GetExpectedHashes();
369 if(_config->FindB("Debug::pkgAcquire::Auth", false) == true)
c46824ce 370 {
08ea7806
DK
371 std::clog << "201 URI Done: " << Owner->DescURI() << endl
372 << "ReceivedHash:" << endl;
373 for (HashStringList::const_iterator hs = ReceivedHashes.begin(); hs != ReceivedHashes.end(); ++hs)
374 std::clog << "\t- " << hs->toStr() << std::endl;
375 std::clog << "ExpectedHash:" << endl;
376 for (HashStringList::const_iterator hs = ExpectedHashes.begin(); hs != ExpectedHashes.end(); ++hs)
377 std::clog << "\t- " << hs->toStr() << std::endl;
378 std::clog << endl;
448c38bd 379 }
448c38bd 380
08ea7806
DK
381 // decide if what we got is what we expected
382 bool consideredOkay = false;
383 if (ExpectedHashes.usable())
384 {
385 if (ReceivedHashes.usable() == false)
386 {
387 /* IMS-Hits can't be checked here as we will have uncompressed file,
388 but the hashes for the compressed file. What we have was good through
389 so all we have to ensure later is that we are not stalled. */
390 consideredOkay = isIMSHit;
391 }
392 else if (ReceivedHashes == ExpectedHashes)
393 consideredOkay = true;
394 else
395 consideredOkay = false;
448c38bd 396
08ea7806
DK
397 }
398 else if (Owner->HashesRequired() == true)
399 consideredOkay = false;
400 else
401 consideredOkay = true;
448c38bd 402
08ea7806 403 if (consideredOkay == true)
448c38bd 404 {
08ea7806
DK
405 Owner->Done(Message, ReceivedHashes, Config);
406
407 // Log that we are done
408 if (Log != 0)
448c38bd 409 {
08ea7806
DK
410 if (isIMSHit)
411 Log->IMSHit(Owner->GetItemDesc());
412 else
413 Log->Done(Owner->GetItemDesc());
448c38bd 414 }
448c38bd 415 }
08ea7806
DK
416 else
417 {
418 Owner->Status = pkgAcquire::Item::StatAuthError;
419 Owner->Failed(Message,Config);
448c38bd 420
08ea7806
DK
421 if (Log != 0)
422 Log->Fail(Owner->GetItemDesc());
423 }
18ef0a78 424 }
08ea7806 425 ItemDone();
c88edf1d 426 break;
448c38bd
DK
427 }
428
0a8a80e5
AL
429 // 400 URI Failure
430 case 400:
c88edf1d
AL
431 {
432 if (Itm == 0)
433 {
5684f71f
DK
434 std::string const msg = LookupTag(Message,"Message");
435 _error->Error("Method gave invalid 400 URI Failure message: %s", msg.c_str());
c88edf1d
AL
436 break;
437 }
438
08ea7806
DK
439 PrepareFiles("400::URIFailure", Itm);
440
c5ccf175
AL
441 // Display update before completion
442 if (Log != 0 && Log->MorePulses == true)
08ea7806
DK
443 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
444 Log->Pulse((*O)->GetOwner());
359e1c4f 445
08ea7806 446 std::vector<Item*> const ItmOwners = Itm->Owners;
c88edf1d 447 OwnerQ->ItemDone(Itm);
08ea7806 448 Itm = NULL;
7e5f33eb 449
08ea7806
DK
450 for (pkgAcquire::Queue::QItem::owner_iterator O = ItmOwners.begin(); O != ItmOwners.end(); ++O)
451 {
452 // set some status
453 if(LookupTag(Message,"FailReason") == "Timeout" ||
454 LookupTag(Message,"FailReason") == "TmpResolveFailure" ||
455 LookupTag(Message,"FailReason") == "ResolveFailure" ||
456 LookupTag(Message,"FailReason") == "ConnectionRefused")
457 (*O)->Status = pkgAcquire::Item::StatTransientNetworkError;
7e5f33eb 458
08ea7806 459 (*O)->Failed(Message,Config);
7d8afa39 460
08ea7806
DK
461 if (Log != 0)
462 Log->Fail((*O)->GetItemDesc());
463 }
464 ItemDone();
7d8afa39 465
c88edf1d 466 break;
448c38bd
DK
467 }
468
0a8a80e5
AL
469 // 401 General Failure
470 case 401:
b2e465d6 471 _error->Error("Method %s General failure: %s",Access.c_str(),LookupTag(Message,"Message").c_str());
0a8a80e5 472 break;
448c38bd 473
542ec555
AL
474 // 403 Media Change
475 case 403:
448c38bd 476 MediaChange(Message);
542ec555 477 break;
448c38bd 478 }
3b5421b4
AL
479 }
480 return true;
481}
482 /*}}}*/
483// Worker::Capabilities - 100 Capabilities handler /*{{{*/
484// ---------------------------------------------------------------------
485/* This parses the capabilities message and dumps it into the configuration
486 structure. */
487bool pkgAcquire::Worker::Capabilities(string Message)
488{
489 if (Config == 0)
490 return true;
448c38bd 491
3b5421b4
AL
492 Config->Version = LookupTag(Message,"Version");
493 Config->SingleInstance = StringToBool(LookupTag(Message,"Single-Instance"),false);
0a8a80e5
AL
494 Config->Pipeline = StringToBool(LookupTag(Message,"Pipeline"),false);
495 Config->SendConfig = StringToBool(LookupTag(Message,"Send-Config"),false);
e331f6ed 496 Config->LocalOnly = StringToBool(LookupTag(Message,"Local-Only"),false);
8e5fc8f5 497 Config->NeedsCleanup = StringToBool(LookupTag(Message,"Needs-Cleanup"),false);
459681d3 498 Config->Removable = StringToBool(LookupTag(Message,"Removable"),false);
3b5421b4
AL
499
500 // Some debug text
501 if (Debug == true)
502 {
503 clog << "Configured access method " << Config->Access << endl;
459681d3
AL
504 clog << "Version:" << Config->Version <<
505 " SingleInstance:" << Config->SingleInstance <<
448c38bd
DK
506 " Pipeline:" << Config->Pipeline <<
507 " SendConfig:" << Config->SendConfig <<
508 " LocalOnly: " << Config->LocalOnly <<
509 " NeedsCleanup: " << Config->NeedsCleanup <<
459681d3 510 " Removable: " << Config->Removable << endl;
3b5421b4 511 }
448c38bd 512
542ec555
AL
513 return true;
514}
515 /*}}}*/
516// Worker::MediaChange - Request a media change /*{{{*/
517// ---------------------------------------------------------------------
518/* */
519bool pkgAcquire::Worker::MediaChange(string Message)
520{
80a26ed1 521 int status_fd = _config->FindI("APT::Status-Fd",-1);
448c38bd 522 if(status_fd > 0)
80a26ed1
MV
523 {
524 string Media = LookupTag(Message,"Media");
448c38bd 525 string Drive = LookupTag(Message,"Drive");
80a26ed1 526 ostringstream msg,status;
1a82c63e
MV
527 ioprintf(msg,_("Please insert the disc labeled: "
528 "'%s' "
529 "in the drive '%s' and press enter."),
530 Media.c_str(),Drive.c_str());
80a26ed1 531 status << "media-change: " // message
1a82c63e
MV
532 << Media << ":" // media
533 << Drive << ":" // drive
534 << msg.str() // l10n message
80a26ed1 535 << endl;
31bda500
DK
536
537 std::string const dlstatus = status.str();
d68d65ad 538 FileFd::Write(status_fd, dlstatus.c_str(), dlstatus.size());
80a26ed1
MV
539 }
540
542ec555
AL
541 if (Log == 0 || Log->MediaChange(LookupTag(Message,"Media"),
542 LookupTag(Message,"Drive")) == false)
543 {
544 char S[300];
96bc43c4 545 snprintf(S,sizeof(S),"603 Media Changed\nFailed: true\n\n");
542ec555
AL
546 if (Debug == true)
547 clog << " -> " << Access << ':' << QuoteString(S,"\n") << endl;
548 OutQueue += S;
549 OutReady = true;
550 return true;
551 }
552
553 char S[300];
96bc43c4 554 snprintf(S,sizeof(S),"603 Media Changed\n\n");
542ec555
AL
555 if (Debug == true)
556 clog << " -> " << Access << ':' << QuoteString(S,"\n") << endl;
557 OutQueue += S;
558 OutReady = true;
3b5421b4
AL
559 return true;
560}
0118833a 561 /*}}}*/
0a8a80e5
AL
562// Worker::SendConfiguration - Send the config to the method /*{{{*/
563// ---------------------------------------------------------------------
564/* */
565bool pkgAcquire::Worker::SendConfiguration()
566{
567 if (Config->SendConfig == false)
568 return true;
569
570 if (OutFd == -1)
571 return false;
0a8a80e5 572
d280d03a 573 /* Write out all of the configuration directives by walking the
0a8a80e5 574 configuration tree */
d280d03a
DK
575 std::ostringstream Message;
576 Message << "601 Configuration\n";
577 _config->Dump(Message, NULL, "Config-Item: %F=%V\n", false);
578 Message << '\n';
0a8a80e5
AL
579
580 if (Debug == true)
d280d03a
DK
581 clog << " -> " << Access << ':' << QuoteString(Message.str(),"\n") << endl;
582 OutQueue += Message.str();
583 OutReady = true;
584
0a8a80e5
AL
585 return true;
586}
587 /*}}}*/
588// Worker::QueueItem - Add an item to the outbound queue /*{{{*/
589// ---------------------------------------------------------------------
590/* Send a URI Acquire message to the method */
591bool pkgAcquire::Worker::QueueItem(pkgAcquire::Queue::QItem *Item)
592{
593 if (OutFd == -1)
594 return false;
448c38bd 595
0a8a80e5
AL
596 string Message = "600 URI Acquire\n";
597 Message.reserve(300);
598 Message += "URI: " + Item->URI;
599 Message += "\nFilename: " + Item->Owner->DestFile;
08ea7806
DK
600
601 HashStringList const hsl = Item->GetExpectedHashes();
d003a557
DK
602 for (HashStringList::const_iterator hs = hsl.begin(); hs != hsl.end(); ++hs)
603 Message += "\nExpected-" + hs->HashType() + ": " + hs->HashValue();
08ea7806
DK
604
605 if (hsl.FileSize() == 0)
c48eea97 606 {
08ea7806
DK
607 unsigned long long FileSize = Item->GetMaximumSize();
608 if(FileSize > 0)
609 {
610 string MaximumSize;
611 strprintf(MaximumSize, "%llu", FileSize);
612 Message += "\nMaximum-Size: " + MaximumSize;
613 }
c48eea97 614 }
08ea7806
DK
615
616 Item->SyncDestinationFiles();
617 Message += Item->Custom600Headers();
0a8a80e5 618 Message += "\n\n";
359e1c4f
DK
619
620 if (RealFileExists(Item->Owner->DestFile))
621 {
622 std::string SandboxUser = _config->Find("APT::Sandbox::User");
623 ChangeOwnerAndPermissionOfFile("Item::QueueURI", Item->Owner->DestFile.c_str(),
624 SandboxUser.c_str(), "root", 0600);
625 }
626
0a8a80e5
AL
627 if (Debug == true)
628 clog << " -> " << Access << ':' << QuoteString(Message,"\n") << endl;
629 OutQueue += Message;
630 OutReady = true;
448c38bd 631
0a8a80e5
AL
632 return true;
633}
634 /*}}}*/
635// Worker::OutFdRead - Out bound FD is ready /*{{{*/
636// ---------------------------------------------------------------------
637/* */
638bool pkgAcquire::Worker::OutFdReady()
639{
ee7af1bd
YY
640 int Res;
641 do
642 {
643 Res = write(OutFd,OutQueue.c_str(),OutQueue.length());
644 }
645 while (Res < 0 && errno == EINTR);
646
647 if (Res <= 0)
0a8a80e5 648 return MethodFailure();
ee7af1bd
YY
649
650 OutQueue.erase(0,Res);
0a8a80e5
AL
651 if (OutQueue.empty() == true)
652 OutReady = false;
448c38bd 653
0a8a80e5
AL
654 return true;
655}
656 /*}}}*/
657// Worker::InFdRead - In bound FD is ready /*{{{*/
658// ---------------------------------------------------------------------
659/* */
660bool pkgAcquire::Worker::InFdReady()
661{
662 if (ReadMessages() == false)
663 return false;
664 RunMessages();
665 return true;
666}
667 /*}}}*/
668// Worker::MethodFailure - Called when the method fails /*{{{*/
669// ---------------------------------------------------------------------
1e3f4083 670/* This is called when the method is believed to have failed, probably because
0a8a80e5
AL
671 read returned -1. */
672bool pkgAcquire::Worker::MethodFailure()
673{
76d97c26 674 _error->Error("Method %s has died unexpectedly!",Access.c_str());
448c38bd 675
ab7f4d7c
MV
676 // do not reap the child here to show meaningfull error to the user
677 ExecWait(Process,Access.c_str(),false);
0a8a80e5
AL
678 Process = -1;
679 close(InFd);
680 close(OutFd);
681 InFd = -1;
682 OutFd = -1;
683 OutReady = false;
684 InReady = false;
685 OutQueue = string();
686 MessageQueue.erase(MessageQueue.begin(),MessageQueue.end());
448c38bd 687
0a8a80e5
AL
688 return false;
689}
690 /*}}}*/
448c38bd 691// Worker::Pulse - Called periodically /*{{{*/
8267fe24
AL
692// ---------------------------------------------------------------------
693/* */
694void pkgAcquire::Worker::Pulse()
695{
696 if (CurrentItem == 0)
697 return;
448c38bd 698
8267fe24
AL
699 struct stat Buf;
700 if (stat(CurrentItem->Owner->DestFile.c_str(),&Buf) != 0)
701 return;
702 CurrentSize = Buf.st_size;
703}
704 /*}}}*/
705// Worker::ItemDone - Called when the current item is finished /*{{{*/
706// ---------------------------------------------------------------------
707/* */
708void pkgAcquire::Worker::ItemDone()
709{
710 CurrentItem = 0;
711 CurrentSize = 0;
712 TotalSize = 0;
713 Status = string();
714}
715 /*}}}*/
08ea7806
DK
716void pkgAcquire::Worker::PrepareFiles(char const * const caller, pkgAcquire::Queue::QItem const * const Itm)/*{{{*/
717{
718 if (RealFileExists(Itm->Owner->DestFile))
719 {
720 ChangeOwnerAndPermissionOfFile(caller, Itm->Owner->DestFile.c_str(), "root", "root", 0644);
721 std::string const filename = Itm->Owner->DestFile;
722 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
723 {
724 pkgAcquire::Item const * const Owner = *O;
725 if (Owner->DestFile == filename)
726 continue;
727 unlink(Owner->DestFile.c_str());
728 if (link(filename.c_str(), Owner->DestFile.c_str()) != 0)
729 {
730 // diferent mounts can't happen for us as we download to lists/ by default,
731 // but if the system is reused by others the locations can potentially be on
732 // different disks, so use symlink as poor-men replacement.
733 // FIXME: Real copying as last fallback, but that is costly, so offload to a method preferable
734 if (symlink(filename.c_str(), Owner->DestFile.c_str()) != 0)
735 _error->Error("Can't create (sym)link of file %s to %s", filename.c_str(), Owner->DestFile.c_str());
736 }
737 }
738 }
739 else
740 {
741 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
742 unlink((*O)->DestFile.c_str());
743 }
744}
745 /*}}}*/