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