]>
git.saurik.com Git - apt.git/blob - apt-pkg/acquire-method.cc
   1 // -*- mode: cpp; mode: fold -*- 
   3 // $Id: acquire-method.cc,v 1.27.2.1 2003/12/24 23:09:17 mdz Exp $ 
   4 /* ###################################################################### 
   8    This is a skeleton class that implements most of the functionality 
   9    of a method and some useful functions to make method implementation 
  10    simpler. The methods all derive this and specialize it. The most 
  11    complex implementation is the http method which needs to provide 
  12    pipelining, it runs the message engine at the same time it is  
  15    ##################################################################### */ 
  17 // Include Files                                                        /*{{{*/ 
  20 #include <apt-pkg/acquire-method.h> 
  21 #include <apt-pkg/error.h> 
  22 #include <apt-pkg/configuration.h> 
  23 #include <apt-pkg/strutl.h> 
  24 #include <apt-pkg/fileutl.h> 
  25 #include <apt-pkg/hashes.h> 
  26 #include <apt-pkg/md5.h> 
  27 #include <apt-pkg/sha1.h> 
  28 #include <apt-pkg/sha2.h> 
  42 // AcqMethod::pkgAcqMethod - Constructor                                /*{{{*/ 
  43 // --------------------------------------------------------------------- 
  44 /* This constructs the initialization text */ 
  45 pkgAcqMethod::pkgAcqMethod(const char *Ver
,unsigned long Flags
) 
  47    std::cout 
<< "100 Capabilities\n" 
  48              << "Version: " << Ver 
<< "\n"; 
  50    if ((Flags 
& SingleInstance
) == SingleInstance
) 
  51       std::cout 
<< "Single-Instance: true\n"; 
  53    if ((Flags 
& Pipeline
) == Pipeline
) 
  54       std::cout 
<< "Pipeline: true\n"; 
  56    if ((Flags 
& SendConfig
) == SendConfig
) 
  57       std::cout 
<< "Send-Config: true\n"; 
  59    if ((Flags 
& LocalOnly
) == LocalOnly
) 
  60       std::cout 
<<"Local-Only: true\n"; 
  62    if ((Flags 
& NeedsCleanup
) == NeedsCleanup
) 
  63       std::cout 
<< "Needs-Cleanup: true\n"; 
  65    if ((Flags 
& Removable
) == Removable
) 
  66       std::cout 
<< "Removable: true\n"; 
  68    std::cout 
<< "\n" << std::flush
; 
  70    SetNonBlock(STDIN_FILENO
,true); 
  76 // AcqMethod::Fail - A fetch has failed                                 /*{{{*/ 
  77 // --------------------------------------------------------------------- 
  79 void pkgAcqMethod::Fail(bool Transient
) 
  81    string Err 
= "Undetermined Error"; 
  82    if (_error
->empty() == false) 
  83       _error
->PopMessage(Err
);    
  88 // AcqMethod::Fail - A fetch has failed                                 /*{{{*/ 
  89 // --------------------------------------------------------------------- 
  91 void pkgAcqMethod::Fail(string Err
,bool Transient
) 
  93    // Strip out junk from the error messages 
  94    for (string::iterator I 
= Err
.begin(); I 
!= Err
.end(); ++I
) 
 104       std::cout 
<< "400 URI Failure\nURI: " << Queue
->Uri 
<< "\n" 
 105                 << "Message: " << Err
; 
 106       if (IP
.empty() == false && _config
->FindB("Acquire::Failure::ShowIP", true) == true) 
 107          std::cout 
<< " " << IP
; 
 112       std::cout 
<< "400 URI Failure\nURI: <UNKNOWN>\nMessage: " << Err 
<< "\n"; 
 114    if(FailReason
.empty() == false) 
 115       std::cout 
<< "FailReason: " << FailReason 
<< "\n"; 
 116    if (UsedMirror
.empty() == false) 
 117       std::cout 
<< "UsedMirror: " << UsedMirror 
<< "\n"; 
 118    // Set the transient flag 
 119    if (Transient 
== true) 
 120       std::cout 
<< "Transient-Failure: true\n"; 
 122    std::cout 
<< "\n" << std::flush
; 
 125 // AcqMethod::DropPrivsOrDie - Drop privileges or die           /*{{{*/ 
 126 // --------------------------------------------------------------------- 
 128 void pkgAcqMethod::DropPrivsOrDie() 
 130    if (!DropPrivileges()) { 
 132       exit(112);        /* call the european emergency number */ 
 137 // AcqMethod::URIStart - Indicate a download is starting                /*{{{*/ 
 138 // --------------------------------------------------------------------- 
 140 void pkgAcqMethod::URIStart(FetchResult 
&Res
) 
 145    std::cout 
<< "200 URI Start\n" 
 146              << "URI: " << Queue
->Uri 
<< "\n"; 
 148       std::cout 
<< "Size: " << Res
.Size 
<< "\n"; 
 150    if (Res
.LastModified 
!= 0) 
 151       std::cout 
<< "Last-Modified: " << TimeRFC1123(Res
.LastModified
) << "\n"; 
 153    if (Res
.ResumePoint 
!= 0) 
 154       std::cout 
<< "Resume-Point: " << Res
.ResumePoint 
<< "\n"; 
 156    if (UsedMirror
.empty() == false) 
 157       std::cout 
<< "UsedMirror: " << UsedMirror 
<< "\n"; 
 159    std::cout 
<< "\n" << std::flush
; 
 162 // AcqMethod::URIDone - A URI is finished                               /*{{{*/ 
 163 // --------------------------------------------------------------------- 
 165 static void printHashStringList(HashStringList 
const * const list
) 
 167       for (HashStringList::const_iterator hash 
= list
->begin(); hash 
!= list
->end(); ++hash
) 
 169          // very old compatibility name for MD5Sum 
 170          if (hash
->HashType() == "MD5Sum") 
 171             std::cout 
<< "MD5-Hash: " << hash
->HashValue() << "\n"; 
 172          std::cout 
<< hash
->HashType() << "-Hash: " << hash
->HashValue() << "\n"; 
 175 void pkgAcqMethod::URIDone(FetchResult 
&Res
, FetchResult 
*Alt
) 
 180    std::cout 
<< "201 URI Done\n" 
 181              << "URI: " << Queue
->Uri 
<< "\n"; 
 183    if (Res
.Filename
.empty() == false) 
 184       std::cout 
<< "Filename: " << Res
.Filename 
<< "\n"; 
 187       std::cout 
<< "Size: " << Res
.Size 
<< "\n"; 
 189    if (Res
.LastModified 
!= 0) 
 190       std::cout 
<< "Last-Modified: " << TimeRFC1123(Res
.LastModified
) << "\n"; 
 192    printHashStringList(&Res
.Hashes
); 
 194    if (UsedMirror
.empty() == false) 
 195       std::cout 
<< "UsedMirror: " << UsedMirror 
<< "\n"; 
 196    if (Res
.GPGVOutput
.empty() == false) 
 198       std::cout 
<< "GPGVOutput:\n"; 
 199       for (vector
<string
>::const_iterator I 
= Res
.GPGVOutput
.begin(); 
 200            I 
!= Res
.GPGVOutput
.end(); ++I
) 
 201          std::cout 
<< " " << *I 
<< "\n"; 
 204    if (Res
.ResumePoint 
!= 0) 
 205       std::cout 
<< "Resume-Point: " << Res
.ResumePoint 
<< "\n"; 
 207    if (Res
.IMSHit 
== true) 
 208       std::cout 
<< "IMS-Hit: true\n"; 
 212       if (Alt
->Filename
.empty() == false) 
 213          std::cout 
<< "Alt-Filename: " << Alt
->Filename 
<< "\n"; 
 216          std::cout 
<< "Alt-Size: " << Alt
->Size 
<< "\n"; 
 218       if (Alt
->LastModified 
!= 0) 
 219          std::cout 
<< "Alt-Last-Modified: " << TimeRFC1123(Alt
->LastModified
) << "\n"; 
 221       printHashStringList(&Alt
->Hashes
); 
 223       if (Alt
->IMSHit 
== true) 
 224          std::cout 
<< "Alt-IMS-Hit: true\n"; 
 227    std::cout 
<< "\n" << std::flush
; 
 231 // AcqMethod::MediaFail - Syncronous request for new media              /*{{{*/ 
 232 // --------------------------------------------------------------------- 
 233 /* This sends a 403 Media Failure message to the APT and waits for it 
 235 bool pkgAcqMethod::MediaFail(string Required
,string Drive
) 
 237    fprintf(stdout
, "403 Media Failure\nMedia: %s\nDrive: %s\n", 
 238             Required
.c_str(),Drive
.c_str()); 
 239    std::cout 
<< "\n" << std::flush
; 
 241    vector
<string
> MyMessages
; 
 243    /* Here we read messages until we find a 603, each non 603 message is 
 244       appended to the main message list for later processing */ 
 247       if (WaitFd(STDIN_FILENO
) == false) 
 250       if (ReadMessages(STDIN_FILENO
,MyMessages
) == false) 
 253       string Message 
= MyMessages
.front(); 
 254       MyMessages
.erase(MyMessages
.begin()); 
 256       // Fetch the message number 
 258       int Number 
= strtol(Message
.c_str(),&End
,10); 
 259       if (End 
== Message
.c_str()) 
 261          cerr 
<< "Malformed message!" << endl
; 
 268          while (MyMessages
.empty() == false) 
 270             Messages
.push_back(MyMessages
.front()); 
 271             MyMessages
.erase(MyMessages
.begin()); 
 274          return !StringToBool(LookupTag(Message
,"Failed"),false); 
 277       Messages
.push_back(Message
); 
 281 // AcqMethod::Configuration - Handle the configuration message          /*{{{*/ 
 282 // --------------------------------------------------------------------- 
 283 /* This parses each configuration entry and puts it into the _config  
 284    Configuration class. */ 
 285 bool pkgAcqMethod::Configuration(string Message
) 
 287    ::Configuration 
&Cnf 
= *_config
; 
 289    const char *I 
= Message
.c_str(); 
 290    const char *MsgEnd 
= I 
+ Message
.length(); 
 292    unsigned int Length 
= strlen("Config-Item"); 
 293    for (; I 
+ Length 
< MsgEnd
; I
++) 
 296       if (I
[Length
] != ':' || stringcasecmp(I
,I
+Length
,"Config-Item") != 0) 
 301       for (; I 
< MsgEnd 
&& *I 
== ' '; I
++); 
 302       const char *Equals 
= (const char*) memchr(I
, '=', MsgEnd 
- I
); 
 305       const char *End 
= (const char*) memchr(Equals
, '\n', MsgEnd 
- Equals
); 
 309       Cnf
.Set(DeQuoteString(string(I
,Equals
-I
)), 
 310               DeQuoteString(string(Equals
+1,End
-Equals
-1))); 
 317 // AcqMethod::Run - Run the message engine                              /*{{{*/ 
 318 // --------------------------------------------------------------------- 
 319 /* Fetch any messages and execute them. In single mode it returns 1 if 
 320    there are no more available messages - any other result is a  
 321    fatal failure code! */ 
 322 int pkgAcqMethod::Run(bool Single
) 
 326       // Block if the message queue is empty 
 327       if (Messages
.empty() == true) 
 330             if (WaitFd(STDIN_FILENO
) == false) 
 332          if (ReadMessages(STDIN_FILENO
,Messages
) == false) 
 336       // Single mode exits if the message queue is empty 
 337       if (Single 
== true && Messages
.empty() == true) 
 340       string Message 
= Messages
.front(); 
 341       Messages
.erase(Messages
.begin()); 
 343       // Fetch the message number 
 345       int Number 
= strtol(Message
.c_str(),&End
,10); 
 346       if (End 
== Message
.c_str()) 
 348          cerr 
<< "Malformed message!" << endl
; 
 355          if (Configuration(Message
) == false) 
 361             FetchItem 
*Tmp 
= new FetchItem
; 
 363             Tmp
->Uri 
= LookupTag(Message
,"URI"); 
 364             Tmp
->DestFile 
= LookupTag(Message
,"FileName"); 
 365             if (RFC1123StrToTime(LookupTag(Message
,"Last-Modified").c_str(),Tmp
->LastModified
) == false) 
 366                Tmp
->LastModified 
= 0; 
 367             Tmp
->IndexFile 
= StringToBool(LookupTag(Message
,"Index-File"),false); 
 368             Tmp
->FailIgnore 
= StringToBool(LookupTag(Message
,"Fail-Ignore"),false); 
 369             Tmp
->ExpectedHashes 
= HashStringList(); 
 370             for (char const * const * t 
= HashString::SupportedHashes(); *t 
!= NULL
; ++t
) 
 372                std::string tag 
= "Expected-"; 
 374                std::string 
const hash 
= LookupTag(Message
, tag
.c_str()); 
 375                if (hash
.empty() == false) 
 376                   Tmp
->ExpectedHashes
.push_back(HashString(*t
, hash
)); 
 379             if (Tmp
->ExpectedHashes
.FileSize() > 0) 
 380                Tmp
->MaximumSize 
= Tmp
->ExpectedHashes
.FileSize(); 
 382                Tmp
->MaximumSize 
= strtoll(LookupTag(Message
, "Maximum-Size", "0").c_str(), &End
, 10); 
 385             // Append it to the list 
 386             FetchItem 
**I 
= &Queue
; 
 387             for (; *I 
!= 0; I 
= &(*I
)->Next
); 
 392             // Notify that this item is to be fetched. 
 393             if (URIAcquire(Message
, Tmp
) == false) 
 405 // AcqMethod::PrintStatus - privately really send a log/status message  /*{{{*/ 
 406 void pkgAcqMethod::PrintStatus(char const * const header
, const char* Format
, 
 409    string CurrentURI 
= "<UNKNOWN>"; 
 411       CurrentURI 
= Queue
->Uri
; 
 412    if (UsedMirror
.empty() == true) 
 413       fprintf(stdout
, "%s\nURI: %s\nMessage: ", 
 414               header
, CurrentURI
.c_str()); 
 416       fprintf(stdout
, "%s\nURI: %s\nUsedMirror: %s\nMessage: ", 
 417               header
, CurrentURI
.c_str(), UsedMirror
.c_str()); 
 418    vfprintf(stdout
,Format
,args
); 
 419    std::cout 
<< "\n\n" << std::flush
; 
 422 // AcqMethod::Log - Send a log message                                  /*{{{*/ 
 423 // --------------------------------------------------------------------- 
 425 void pkgAcqMethod::Log(const char *Format
,...) 
 428    va_start(args
,Format
); 
 429    PrintStatus("101 Log", Format
, args
); 
 433 // AcqMethod::Status - Send a status message                            /*{{{*/ 
 434 // --------------------------------------------------------------------- 
 436 void pkgAcqMethod::Status(const char *Format
,...) 
 439    va_start(args
,Format
); 
 440    PrintStatus("102 Status", Format
, args
); 
 444 // AcqMethod::Redirect - Send a redirect message                       /*{{{*/ 
 445 // --------------------------------------------------------------------- 
 446 /* This method sends the redirect message and dequeues the item as 
 447  * the worker will enqueue again later on to the right queue */ 
 448 void pkgAcqMethod::Redirect(const string 
&NewURI
) 
 450    std::cout 
<< "103 Redirect\nURI: " << Queue
->Uri 
<< "\n" 
 451              << "New-URI: " << NewURI 
<< "\n" 
 452              << "\n" << std::flush
; 
 456 // AcqMethod::FetchResult::FetchResult - Constructor                    /*{{{*/ 
 457 // --------------------------------------------------------------------- 
 459 pkgAcqMethod::FetchResult::FetchResult() : LastModified(0), 
 460                                    IMSHit(false), Size(0), ResumePoint(0), d(NULL
) 
 464 // AcqMethod::FetchResult::TakeHashes - Load hashes                     /*{{{*/ 
 465 // --------------------------------------------------------------------- 
 466 /* This hides the number of hashes we are supporting from the caller.  
 467    It just deals with the hash class. */ 
 468 void pkgAcqMethod::FetchResult::TakeHashes(class Hashes 
&Hash
) 
 470    Hashes 
= Hash
.GetHashStringList(); 
 473 void pkgAcqMethod::Dequeue() {                                          /*{{{*/ 
 474    FetchItem 
const * const Tmp 
= Queue
; 
 476    if (Tmp 
== QueueBack
) 
 481 pkgAcqMethod::~pkgAcqMethod() {} 
 483 pkgAcqMethod::FetchItem::FetchItem() : d(NULL
) {} 
 484 pkgAcqMethod::FetchItem::~FetchItem() {} 
 486 pkgAcqMethod::FetchResult::~FetchResult() {}