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