]> git.saurik.com Git - apt.git/blame - apt-pkg/acquire-worker.cc
Add GetPriority(VerIterator) to pkgDepCache::Policy
[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 206 string URI = LookupTag(Message,"URI");
a4b8112b 207 pkgAcquire::Queue::QItem *Itm = NULL;
c88edf1d
AL
208 if (URI.empty() == false)
209 Itm = OwnerQ->FindItem(URI,this);
196fd136 210
a4b8112b 211 if (Itm != NULL)
196fd136 212 {
a4b8112b
DK
213 // update used mirror
214 string UsedMirror = LookupTag(Message,"UsedMirror", "");
215 if (UsedMirror.empty() == false)
216 {
217 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
218 (*O)->UsedMirror = UsedMirror;
219
220 if (Itm->Description.find(" ") != string::npos)
221 Itm->Description.replace(0, Itm->Description.find(" "), UsedMirror);
222 }
196fd136 223 }
448c38bd 224
3b5421b4
AL
225 // Determine the message number and dispatch
226 switch (Number)
227 {
0a8a80e5 228 // 100 Capabilities
3b5421b4
AL
229 case 100:
230 if (Capabilities(Message) == false)
231 return _error->Error("Unable to process Capabilities message from %s",Access.c_str());
232 break;
448c38bd 233
0a8a80e5
AL
234 // 101 Log
235 case 101:
236 if (Debug == true)
237 clog << " <- (log) " << LookupTag(Message,"Message") << endl;
238 break;
448c38bd 239
0a8a80e5
AL
240 // 102 Status
241 case 102:
242 Status = LookupTag(Message,"Message");
243 break;
448c38bd 244
15d7e515
MV
245 // 103 Redirect
246 case 103:
247 {
248 if (Itm == 0)
249 {
250 _error->Error("Method gave invalid 103 Redirect message");
251 break;
252 }
448c38bd 253
a4b8112b 254 std::string const NewURI = LookupTag(Message,"New-URI",URI.c_str());
15d7e515 255 Itm->URI = NewURI;
5674f6b3
RG
256
257 ItemDone();
258
5674f6b3 259 // Change the status so that it can be dequeued
08ea7806 260 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
a4b8112b 261 (*O)->Status = pkgAcquire::Item::StatIdle;
5674f6b3
RG
262 // Mark the item as done (taking care of all queues)
263 // and then put it in the main queue again
08ea7806 264 std::vector<Item*> const ItmOwners = Itm->Owners;
5674f6b3 265 OwnerQ->ItemDone(Itm);
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;
a4b8112b
DK
270 pkgAcquire::ItemDesc &desc = Owner->GetItemDesc();
271 // if we change site, treat it as a mirror change
272 if (URI::SiteOnly(NewURI) != URI::SiteOnly(desc.URI))
273 {
274 std::string const OldSite = desc.Description.substr(0, desc.Description.find(" "));
275 if (likely(APT::String::Startswith(desc.URI, OldSite)))
276 {
277 std::string const OldExtra = desc.URI.substr(OldSite.length() + 1);
278 if (likely(APT::String::Endswith(NewURI, OldExtra)))
279 {
280 std::string const NewSite = NewURI.substr(0, NewURI.length() - OldExtra.length());
281 Owner->UsedMirror = URI::ArchiveOnly(NewSite);
282 if (desc.Description.find(" ") != string::npos)
283 desc.Description.replace(0, desc.Description.find(" "), Owner->UsedMirror);
284 }
285 }
286 }
08ea7806
DK
287 desc.URI = NewURI;
288 OwnerQ->Owner->Enqueue(desc);
5674f6b3 289
08ea7806 290 if (Log != 0)
a4b8112b 291 Log->Done(desc);
08ea7806 292 }
15d7e515
MV
293 break;
294 }
448c38bd 295
0a8a80e5
AL
296 // 200 URI Start
297 case 200:
c88edf1d
AL
298 {
299 if (Itm == 0)
300 {
93bf083d 301 _error->Error("Method gave invalid 200 URI Start message");
c88edf1d
AL
302 break;
303 }
448c38bd 304
c88edf1d
AL
305 CurrentItem = Itm;
306 CurrentSize = 0;
650faab0
DK
307 TotalSize = strtoull(LookupTag(Message,"Size","0").c_str(), NULL, 10);
308 ResumePoint = strtoull(LookupTag(Message,"Resume-Point","0").c_str(), NULL, 10);
08ea7806
DK
309 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
310 {
311 (*O)->Start(Message, TotalSize);
448c38bd 312
08ea7806
DK
313 // Display update before completion
314 if (Log != 0)
315 {
316 if (Log->MorePulses == true)
317 Log->Pulse((*O)->GetOwner());
318 Log->Fetch((*O)->GetItemDesc());
319 }
320 }
8267fe24 321
c88edf1d
AL
322 break;
323 }
448c38bd 324
0a8a80e5
AL
325 // 201 URI Done
326 case 201:
c88edf1d
AL
327 {
328 if (Itm == 0)
329 {
93bf083d 330 _error->Error("Method gave invalid 201 URI Done message");
c88edf1d
AL
331 break;
332 }
448c38bd 333
08ea7806 334 PrepareFiles("201::URIDone", Itm);
359e1c4f 335
c5ccf175
AL
336 // Display update before completion
337 if (Log != 0 && Log->MorePulses == true)
08ea7806
DK
338 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
339 Log->Pulse((*O)->GetOwner());
448c38bd 340
08ea7806 341 std::string const filename = LookupTag(Message, "Filename", Itm->Owner->DestFile.c_str());
20801f61 342 HashStringList ReceivedHashes;
8a8feb29 343 {
08ea7806
DK
344 // see if we got hashes to verify
345 for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
448c38bd 346 {
08ea7806
DK
347 std::string const tagname = std::string(*type) + "-Hash";
348 std::string const hashsum = LookupTag(Message, tagname.c_str());
349 if (hashsum.empty() == false)
350 ReceivedHashes.push_back(HashString(*type, hashsum));
351 }
352 // not all methods always sent Hashes our way
353 if (ReceivedHashes.usable() == false)
354 {
355 HashStringList const ExpectedHashes = Itm->GetExpectedHashes();
356 if (ExpectedHashes.usable() == true && RealFileExists(filename))
357 {
358 Hashes calc(ExpectedHashes);
359 FileFd file(filename, FileFd::ReadOnly, FileFd::None);
360 calc.AddFD(file);
361 ReceivedHashes = calc.GetHashStringList();
362 }
448c38bd
DK
363 }
364 }
b3501edb 365
08ea7806
DK
366 // only local files can refer other filenames and counting them as fetched would be unfair
367 if (Log != NULL && filename != Itm->Owner->DestFile)
368 Log->Fetched(ReceivedHashes.FileSize(),atoi(LookupTag(Message,"Resume-Point","0").c_str()));
369
370 std::vector<Item*> const ItmOwners = Itm->Owners;
371 OwnerQ->ItemDone(Itm);
372 Itm = NULL;
b3501edb 373
448c38bd
DK
374 bool const isIMSHit = StringToBool(LookupTag(Message,"IMS-Hit"),false) ||
375 StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false);
08ea7806 376 for (pkgAcquire::Queue::QItem::owner_iterator O = ItmOwners.begin(); O != ItmOwners.end(); ++O)
8267fe24 377 {
08ea7806
DK
378 pkgAcquire::Item * const Owner = *O;
379 HashStringList const ExpectedHashes = Owner->GetExpectedHashes();
380 if(_config->FindB("Debug::pkgAcquire::Auth", false) == true)
c46824ce 381 {
08ea7806
DK
382 std::clog << "201 URI Done: " << Owner->DescURI() << endl
383 << "ReceivedHash:" << endl;
384 for (HashStringList::const_iterator hs = ReceivedHashes.begin(); hs != ReceivedHashes.end(); ++hs)
385 std::clog << "\t- " << hs->toStr() << std::endl;
386 std::clog << "ExpectedHash:" << endl;
387 for (HashStringList::const_iterator hs = ExpectedHashes.begin(); hs != ExpectedHashes.end(); ++hs)
388 std::clog << "\t- " << hs->toStr() << std::endl;
389 std::clog << endl;
448c38bd 390 }
448c38bd 391
08ea7806
DK
392 // decide if what we got is what we expected
393 bool consideredOkay = false;
394 if (ExpectedHashes.usable())
395 {
396 if (ReceivedHashes.usable() == false)
397 {
398 /* IMS-Hits can't be checked here as we will have uncompressed file,
399 but the hashes for the compressed file. What we have was good through
400 so all we have to ensure later is that we are not stalled. */
401 consideredOkay = isIMSHit;
402 }
403 else if (ReceivedHashes == ExpectedHashes)
404 consideredOkay = true;
405 else
406 consideredOkay = false;
448c38bd 407
08ea7806
DK
408 }
409 else if (Owner->HashesRequired() == true)
410 consideredOkay = false;
411 else
412 consideredOkay = true;
448c38bd 413
dd676dc7
DK
414 if (consideredOkay == true)
415 consideredOkay = Owner->VerifyDone(Message, Config);
416 else // hashsum mismatch
417 Owner->Status = pkgAcquire::Item::StatAuthError;
418
08ea7806 419 if (consideredOkay == true)
448c38bd 420 {
08ea7806 421 Owner->Done(Message, ReceivedHashes, Config);
08ea7806 422 if (Log != 0)
448c38bd 423 {
08ea7806
DK
424 if (isIMSHit)
425 Log->IMSHit(Owner->GetItemDesc());
426 else
427 Log->Done(Owner->GetItemDesc());
448c38bd 428 }
448c38bd 429 }
08ea7806
DK
430 else
431 {
08ea7806 432 Owner->Failed(Message,Config);
08ea7806
DK
433 if (Log != 0)
434 Log->Fail(Owner->GetItemDesc());
435 }
18ef0a78 436 }
08ea7806 437 ItemDone();
c88edf1d 438 break;
448c38bd
DK
439 }
440
0a8a80e5
AL
441 // 400 URI Failure
442 case 400:
c88edf1d
AL
443 {
444 if (Itm == 0)
445 {
5684f71f
DK
446 std::string const msg = LookupTag(Message,"Message");
447 _error->Error("Method gave invalid 400 URI Failure message: %s", msg.c_str());
c88edf1d
AL
448 break;
449 }
450
08ea7806
DK
451 PrepareFiles("400::URIFailure", Itm);
452
c5ccf175
AL
453 // Display update before completion
454 if (Log != 0 && Log->MorePulses == true)
08ea7806
DK
455 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
456 Log->Pulse((*O)->GetOwner());
359e1c4f 457
08ea7806 458 std::vector<Item*> const ItmOwners = Itm->Owners;
c88edf1d 459 OwnerQ->ItemDone(Itm);
08ea7806 460 Itm = NULL;
7e5f33eb 461
08ea7806
DK
462 for (pkgAcquire::Queue::QItem::owner_iterator O = ItmOwners.begin(); O != ItmOwners.end(); ++O)
463 {
464 // set some status
465 if(LookupTag(Message,"FailReason") == "Timeout" ||
466 LookupTag(Message,"FailReason") == "TmpResolveFailure" ||
467 LookupTag(Message,"FailReason") == "ResolveFailure" ||
468 LookupTag(Message,"FailReason") == "ConnectionRefused")
469 (*O)->Status = pkgAcquire::Item::StatTransientNetworkError;
7e5f33eb 470
08ea7806 471 (*O)->Failed(Message,Config);
7d8afa39 472
08ea7806
DK
473 if (Log != 0)
474 Log->Fail((*O)->GetItemDesc());
475 }
476 ItemDone();
7d8afa39 477
c88edf1d 478 break;
448c38bd
DK
479 }
480
0a8a80e5
AL
481 // 401 General Failure
482 case 401:
b2e465d6 483 _error->Error("Method %s General failure: %s",Access.c_str(),LookupTag(Message,"Message").c_str());
0a8a80e5 484 break;
448c38bd 485
542ec555
AL
486 // 403 Media Change
487 case 403:
448c38bd 488 MediaChange(Message);
542ec555 489 break;
448c38bd 490 }
3b5421b4
AL
491 }
492 return true;
493}
494 /*}}}*/
495// Worker::Capabilities - 100 Capabilities handler /*{{{*/
496// ---------------------------------------------------------------------
497/* This parses the capabilities message and dumps it into the configuration
498 structure. */
499bool pkgAcquire::Worker::Capabilities(string Message)
500{
501 if (Config == 0)
502 return true;
448c38bd 503
3b5421b4
AL
504 Config->Version = LookupTag(Message,"Version");
505 Config->SingleInstance = StringToBool(LookupTag(Message,"Single-Instance"),false);
0a8a80e5
AL
506 Config->Pipeline = StringToBool(LookupTag(Message,"Pipeline"),false);
507 Config->SendConfig = StringToBool(LookupTag(Message,"Send-Config"),false);
e331f6ed 508 Config->LocalOnly = StringToBool(LookupTag(Message,"Local-Only"),false);
8e5fc8f5 509 Config->NeedsCleanup = StringToBool(LookupTag(Message,"Needs-Cleanup"),false);
459681d3 510 Config->Removable = StringToBool(LookupTag(Message,"Removable"),false);
3b5421b4
AL
511
512 // Some debug text
513 if (Debug == true)
514 {
515 clog << "Configured access method " << Config->Access << endl;
459681d3
AL
516 clog << "Version:" << Config->Version <<
517 " SingleInstance:" << Config->SingleInstance <<
448c38bd
DK
518 " Pipeline:" << Config->Pipeline <<
519 " SendConfig:" << Config->SendConfig <<
520 " LocalOnly: " << Config->LocalOnly <<
521 " NeedsCleanup: " << Config->NeedsCleanup <<
459681d3 522 " Removable: " << Config->Removable << endl;
3b5421b4 523 }
448c38bd 524
542ec555
AL
525 return true;
526}
527 /*}}}*/
528// Worker::MediaChange - Request a media change /*{{{*/
529// ---------------------------------------------------------------------
530/* */
531bool pkgAcquire::Worker::MediaChange(string Message)
532{
80a26ed1 533 int status_fd = _config->FindI("APT::Status-Fd",-1);
448c38bd 534 if(status_fd > 0)
80a26ed1
MV
535 {
536 string Media = LookupTag(Message,"Media");
448c38bd 537 string Drive = LookupTag(Message,"Drive");
80a26ed1 538 ostringstream msg,status;
1a82c63e
MV
539 ioprintf(msg,_("Please insert the disc labeled: "
540 "'%s' "
94171725 541 "in the drive '%s' and press [Enter]."),
1a82c63e 542 Media.c_str(),Drive.c_str());
80a26ed1 543 status << "media-change: " // message
1a82c63e
MV
544 << Media << ":" // media
545 << Drive << ":" // drive
546 << msg.str() // l10n message
80a26ed1 547 << endl;
31bda500
DK
548
549 std::string const dlstatus = status.str();
d68d65ad 550 FileFd::Write(status_fd, dlstatus.c_str(), dlstatus.size());
80a26ed1
MV
551 }
552
542ec555
AL
553 if (Log == 0 || Log->MediaChange(LookupTag(Message,"Media"),
554 LookupTag(Message,"Drive")) == false)
555 {
556 char S[300];
96bc43c4 557 snprintf(S,sizeof(S),"603 Media Changed\nFailed: true\n\n");
542ec555
AL
558 if (Debug == true)
559 clog << " -> " << Access << ':' << QuoteString(S,"\n") << endl;
560 OutQueue += S;
561 OutReady = true;
562 return true;
563 }
564
565 char S[300];
96bc43c4 566 snprintf(S,sizeof(S),"603 Media Changed\n\n");
542ec555
AL
567 if (Debug == true)
568 clog << " -> " << Access << ':' << QuoteString(S,"\n") << endl;
569 OutQueue += S;
570 OutReady = true;
3b5421b4
AL
571 return true;
572}
0118833a 573 /*}}}*/
0a8a80e5
AL
574// Worker::SendConfiguration - Send the config to the method /*{{{*/
575// ---------------------------------------------------------------------
576/* */
577bool pkgAcquire::Worker::SendConfiguration()
578{
579 if (Config->SendConfig == false)
580 return true;
581
582 if (OutFd == -1)
583 return false;
0a8a80e5 584
d280d03a 585 /* Write out all of the configuration directives by walking the
0a8a80e5 586 configuration tree */
d280d03a
DK
587 std::ostringstream Message;
588 Message << "601 Configuration\n";
589 _config->Dump(Message, NULL, "Config-Item: %F=%V\n", false);
590 Message << '\n';
0a8a80e5
AL
591
592 if (Debug == true)
d280d03a
DK
593 clog << " -> " << Access << ':' << QuoteString(Message.str(),"\n") << endl;
594 OutQueue += Message.str();
595 OutReady = true;
596
0a8a80e5
AL
597 return true;
598}
599 /*}}}*/
600// Worker::QueueItem - Add an item to the outbound queue /*{{{*/
601// ---------------------------------------------------------------------
602/* Send a URI Acquire message to the method */
603bool pkgAcquire::Worker::QueueItem(pkgAcquire::Queue::QItem *Item)
604{
605 if (OutFd == -1)
606 return false;
448c38bd 607
0a8a80e5
AL
608 string Message = "600 URI Acquire\n";
609 Message.reserve(300);
610 Message += "URI: " + Item->URI;
611 Message += "\nFilename: " + Item->Owner->DestFile;
08ea7806
DK
612
613 HashStringList const hsl = Item->GetExpectedHashes();
d003a557
DK
614 for (HashStringList::const_iterator hs = hsl.begin(); hs != hsl.end(); ++hs)
615 Message += "\nExpected-" + hs->HashType() + ": " + hs->HashValue();
08ea7806
DK
616
617 if (hsl.FileSize() == 0)
c48eea97 618 {
08ea7806
DK
619 unsigned long long FileSize = Item->GetMaximumSize();
620 if(FileSize > 0)
621 {
622 string MaximumSize;
623 strprintf(MaximumSize, "%llu", FileSize);
624 Message += "\nMaximum-Size: " + MaximumSize;
625 }
c48eea97 626 }
08ea7806
DK
627
628 Item->SyncDestinationFiles();
629 Message += Item->Custom600Headers();
0a8a80e5 630 Message += "\n\n";
359e1c4f
DK
631
632 if (RealFileExists(Item->Owner->DestFile))
633 {
634 std::string SandboxUser = _config->Find("APT::Sandbox::User");
635 ChangeOwnerAndPermissionOfFile("Item::QueueURI", Item->Owner->DestFile.c_str(),
636 SandboxUser.c_str(), "root", 0600);
637 }
638
0a8a80e5
AL
639 if (Debug == true)
640 clog << " -> " << Access << ':' << QuoteString(Message,"\n") << endl;
641 OutQueue += Message;
642 OutReady = true;
448c38bd 643
0a8a80e5
AL
644 return true;
645}
646 /*}}}*/
647// Worker::OutFdRead - Out bound FD is ready /*{{{*/
648// ---------------------------------------------------------------------
649/* */
650bool pkgAcquire::Worker::OutFdReady()
651{
ee7af1bd
YY
652 int Res;
653 do
654 {
655 Res = write(OutFd,OutQueue.c_str(),OutQueue.length());
656 }
657 while (Res < 0 && errno == EINTR);
658
659 if (Res <= 0)
0a8a80e5 660 return MethodFailure();
ee7af1bd
YY
661
662 OutQueue.erase(0,Res);
0a8a80e5
AL
663 if (OutQueue.empty() == true)
664 OutReady = false;
448c38bd 665
0a8a80e5
AL
666 return true;
667}
668 /*}}}*/
669// Worker::InFdRead - In bound FD is ready /*{{{*/
670// ---------------------------------------------------------------------
671/* */
672bool pkgAcquire::Worker::InFdReady()
673{
674 if (ReadMessages() == false)
675 return false;
676 RunMessages();
677 return true;
678}
679 /*}}}*/
680// Worker::MethodFailure - Called when the method fails /*{{{*/
681// ---------------------------------------------------------------------
1e3f4083 682/* This is called when the method is believed to have failed, probably because
0a8a80e5
AL
683 read returned -1. */
684bool pkgAcquire::Worker::MethodFailure()
685{
76d97c26 686 _error->Error("Method %s has died unexpectedly!",Access.c_str());
448c38bd 687
ab7f4d7c
MV
688 // do not reap the child here to show meaningfull error to the user
689 ExecWait(Process,Access.c_str(),false);
0a8a80e5
AL
690 Process = -1;
691 close(InFd);
692 close(OutFd);
693 InFd = -1;
694 OutFd = -1;
695 OutReady = false;
696 InReady = false;
697 OutQueue = string();
698 MessageQueue.erase(MessageQueue.begin(),MessageQueue.end());
448c38bd 699
0a8a80e5
AL
700 return false;
701}
702 /*}}}*/
448c38bd 703// Worker::Pulse - Called periodically /*{{{*/
8267fe24
AL
704// ---------------------------------------------------------------------
705/* */
706void pkgAcquire::Worker::Pulse()
707{
708 if (CurrentItem == 0)
709 return;
448c38bd 710
8267fe24
AL
711 struct stat Buf;
712 if (stat(CurrentItem->Owner->DestFile.c_str(),&Buf) != 0)
713 return;
714 CurrentSize = Buf.st_size;
715}
716 /*}}}*/
717// Worker::ItemDone - Called when the current item is finished /*{{{*/
718// ---------------------------------------------------------------------
719/* */
720void pkgAcquire::Worker::ItemDone()
721{
722 CurrentItem = 0;
723 CurrentSize = 0;
724 TotalSize = 0;
725 Status = string();
726}
727 /*}}}*/
08ea7806
DK
728void pkgAcquire::Worker::PrepareFiles(char const * const caller, pkgAcquire::Queue::QItem const * const Itm)/*{{{*/
729{
730 if (RealFileExists(Itm->Owner->DestFile))
731 {
732 ChangeOwnerAndPermissionOfFile(caller, Itm->Owner->DestFile.c_str(), "root", "root", 0644);
733 std::string const filename = Itm->Owner->DestFile;
734 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
735 {
736 pkgAcquire::Item const * const Owner = *O;
737 if (Owner->DestFile == filename)
738 continue;
739 unlink(Owner->DestFile.c_str());
740 if (link(filename.c_str(), Owner->DestFile.c_str()) != 0)
741 {
3d8232bf 742 // different mounts can't happen for us as we download to lists/ by default,
08ea7806
DK
743 // but if the system is reused by others the locations can potentially be on
744 // different disks, so use symlink as poor-men replacement.
745 // FIXME: Real copying as last fallback, but that is costly, so offload to a method preferable
746 if (symlink(filename.c_str(), Owner->DestFile.c_str()) != 0)
747 _error->Error("Can't create (sym)link of file %s to %s", filename.c_str(), Owner->DestFile.c_str());
748 }
749 }
750 }
751 else
752 {
753 for (pkgAcquire::Queue::QItem::owner_iterator O = Itm->Owners.begin(); O != Itm->Owners.end(); ++O)
754 unlink((*O)->DestFile.c_str());
755 }
756}
757 /*}}}*/