]>
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 /*{{{*/
18 #include <apt-pkg/acquire-method.h>
19 #include <apt-pkg/error.h>
20 #include <apt-pkg/configuration.h>
21 #include <apt-pkg/strutl.h>
22 #include <apt-pkg/fileutl.h>
23 #include <apt-pkg/hashes.h>
29 #include <sys/signal.h>
34 // AcqMethod::pkgAcqMethod - Constructor /*{{{*/
35 // ---------------------------------------------------------------------
36 /* This constructs the initialization text */
37 pkgAcqMethod::pkgAcqMethod(const char *Ver
,unsigned long Flags
)
41 strcat(End
,"100 Capabilities\n");
42 sprintf(End
+strlen(End
),"Version: %s\n",Ver
);
44 if ((Flags
& SingleInstance
) == SingleInstance
)
45 strcat(End
,"Single-Instance: true\n");
47 if ((Flags
& Pipeline
) == Pipeline
)
48 strcat(End
,"Pipeline: true\n");
50 if ((Flags
& SendConfig
) == SendConfig
)
51 strcat(End
,"Send-Config: true\n");
53 if ((Flags
& LocalOnly
) == LocalOnly
)
54 strcat(End
,"Local-Only: true\n");
56 if ((Flags
& NeedsCleanup
) == NeedsCleanup
)
57 strcat(End
,"Needs-Cleanup: true\n");
59 if ((Flags
& Removable
) == Removable
)
60 strcat(End
,"Removable: true\n");
63 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
66 SetNonBlock(STDIN_FILENO
,true);
72 // AcqMethod::Fail - A fetch has failed /*{{{*/
73 // ---------------------------------------------------------------------
75 void pkgAcqMethod::Fail(bool Transient
)
77 string Err
= "Undetermined Error";
78 if (_error
->empty() == false)
79 _error
->PopMessage(Err
);
84 // AcqMethod::Fail - A fetch has failed /*{{{*/
85 // ---------------------------------------------------------------------
87 void pkgAcqMethod::Fail(string Err
,bool Transient
)
89 // Strip out junk from the error messages
90 for (string::iterator I
= Err
.begin(); I
!= Err
.end(); I
++)
102 End
+= snprintf(S
,sizeof(S
)-50,"400 URI Failure\nURI: %s\n"
103 "Message: %s %s\n",Queue
->Uri
.c_str(), Err
.c_str(), IP
.c_str());
105 FetchItem
*Tmp
= Queue
;
108 if (Tmp
== QueueBack
)
113 End
+= snprintf(S
,sizeof(S
)-50,"400 URI Failure\nURI: <UNKNOWN>\n"
114 "Message: %s\n",Err
.c_str());
116 if(FailReason
.empty() == false)
117 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"FailReason: %s\n",FailReason
.c_str());
118 if (UsedMirror
.empty() == false)
119 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"UsedMirror: %s\n",UsedMirror
.c_str());
120 // Set the transient flag
121 if (Transient
== true)
122 strcat(S
,"Transient-Failure: true\n\n");
126 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
130 // AcqMethod::URIStart - Indicate a download is starting /*{{{*/
131 // ---------------------------------------------------------------------
133 void pkgAcqMethod::URIStart(FetchResult
&Res
)
141 End
+= snprintf(S
,sizeof(S
),"200 URI Start\nURI: %s\n",Queue
->Uri
.c_str());
143 End
+= snprintf(End
,sizeof(S
)-4 - (End
- S
),"Size: %lu\n",Res
.Size
);
145 if (Res
.LastModified
!= 0)
146 End
+= snprintf(End
,sizeof(S
)-4 - (End
- S
),"Last-Modified: %s\n",
147 TimeRFC1123(Res
.LastModified
).c_str());
149 if (Res
.ResumePoint
!= 0)
150 End
+= snprintf(End
,sizeof(S
)-4 - (End
- S
),"Resume-Point: %lu\n",
152 if (UsedMirror
.empty() == false)
153 End
+= snprintf(End
,sizeof(S
)-4 - (End
- S
),"UsedMirror: %s\n",UsedMirror
.c_str());
156 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
160 // AcqMethod::URIDone - A URI is finished /*{{{*/
161 // ---------------------------------------------------------------------
163 void pkgAcqMethod::URIDone(FetchResult
&Res
, FetchResult
*Alt
)
171 End
+= snprintf(S
,sizeof(S
),"201 URI Done\nURI: %s\n",Queue
->Uri
.c_str());
173 if (Res
.Filename
.empty() == false)
174 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Filename: %s\n",Res
.Filename
.c_str());
177 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Size: %lu\n",Res
.Size
);
179 if (Res
.LastModified
!= 0)
180 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Last-Modified: %s\n",
181 TimeRFC1123(Res
.LastModified
).c_str());
183 if (Res
.MD5Sum
.empty() == false)
185 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"MD5-Hash: %s\n",Res
.MD5Sum
.c_str());
186 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"MD5Sum-Hash: %s\n",Res
.MD5Sum
.c_str());
188 if (Res
.SHA1Sum
.empty() == false)
189 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"SHA1-Hash: %s\n",Res
.SHA1Sum
.c_str());
190 if (Res
.SHA256Sum
.empty() == false)
191 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"SHA256-Hash: %s\n",Res
.SHA256Sum
.c_str());
192 if (UsedMirror
.empty() == false)
193 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"UsedMirror: %s\n",UsedMirror
.c_str());
194 if (Res
.GPGVOutput
.size() > 0)
195 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"GPGVOutput:\n");
196 for (vector
<string
>::iterator I
= Res
.GPGVOutput
.begin();
197 I
!= Res
.GPGVOutput
.end(); I
++)
198 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
), " %s\n", (*I
).c_str());
200 if (Res
.ResumePoint
!= 0)
201 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Resume-Point: %lu\n",
204 if (Res
.IMSHit
== true)
205 strcat(End
,"IMS-Hit: true\n");
210 if (Alt
->Filename
.empty() == false)
211 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Alt-Filename: %s\n",Alt
->Filename
.c_str());
214 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Alt-Size: %lu\n",Alt
->Size
);
216 if (Alt
->LastModified
!= 0)
217 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Alt-Last-Modified: %s\n",
218 TimeRFC1123(Alt
->LastModified
).c_str());
220 if (Alt
->MD5Sum
.empty() == false)
221 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Alt-MD5-Hash: %s\n",
222 Alt
->MD5Sum
.c_str());
223 if (Alt
->SHA1Sum
.empty() == false)
224 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Alt-SHA1-Hash: %s\n",
225 Alt
->SHA1Sum
.c_str());
226 if (Alt
->SHA256Sum
.empty() == false)
227 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Alt-SHA256-Hash: %s\n",
228 Alt
->SHA256Sum
.c_str());
230 if (Alt
->IMSHit
== true)
231 strcat(End
,"Alt-IMS-Hit: true\n");
235 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
239 FetchItem
*Tmp
= Queue
;
242 if (Tmp
== QueueBack
)
246 // AcqMethod::MediaFail - Syncronous request for new media /*{{{*/
247 // ---------------------------------------------------------------------
248 /* This sends a 403 Media Failure message to the APT and waits for it
250 bool pkgAcqMethod::MediaFail(string Required
,string Drive
)
253 snprintf(S
,sizeof(S
),"403 Media Failure\nMedia: %s\nDrive: %s\n\n",
254 Required
.c_str(),Drive
.c_str());
256 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
259 vector
<string
> MyMessages
;
261 /* Here we read messages until we find a 603, each non 603 message is
262 appended to the main message list for later processing */
265 if (WaitFd(STDIN_FILENO
) == false)
268 if (ReadMessages(STDIN_FILENO
,MyMessages
) == false)
271 string Message
= MyMessages
.front();
272 MyMessages
.erase(MyMessages
.begin());
274 // Fetch the message number
276 int Number
= strtol(Message
.c_str(),&End
,10);
277 if (End
== Message
.c_str())
279 cerr
<< "Malformed message!" << endl
;
286 while (MyMessages
.empty() == false)
288 Messages
.push_back(MyMessages
.front());
289 MyMessages
.erase(MyMessages
.begin());
292 return !StringToBool(LookupTag(Message
,"Failed"),false);
295 Messages
.push_back(Message
);
299 // AcqMethod::Configuration - Handle the configuration message /*{{{*/
300 // ---------------------------------------------------------------------
301 /* This parses each configuration entry and puts it into the _config
302 Configuration class. */
303 bool pkgAcqMethod::Configuration(string Message
)
305 ::Configuration
&Cnf
= *_config
;
307 const char *I
= Message
.c_str();
308 const char *MsgEnd
= I
+ Message
.length();
310 unsigned int Length
= strlen("Config-Item");
311 for (; I
+ Length
< MsgEnd
; I
++)
314 if (I
[Length
] != ':' || stringcasecmp(I
,I
+Length
,"Config-Item") != 0)
319 for (; I
< MsgEnd
&& *I
== ' '; I
++);
320 const char *Equals
= I
;
321 for (; Equals
< MsgEnd
&& *Equals
!= '='; Equals
++);
322 const char *End
= Equals
;
323 for (; End
< MsgEnd
&& *End
!= '\n'; End
++);
327 Cnf
.Set(DeQuoteString(string(I
,Equals
-I
)),
328 DeQuoteString(string(Equals
+1,End
-Equals
-1)));
335 // AcqMethod::Run - Run the message engine /*{{{*/
336 // ---------------------------------------------------------------------
337 /* Fetch any messages and execute them. In single mode it returns 1 if
338 there are no more available messages - any other result is a
339 fatal failure code! */
340 int pkgAcqMethod::Run(bool Single
)
344 // Block if the message queue is empty
345 if (Messages
.empty() == true)
348 if (WaitFd(STDIN_FILENO
) == false)
350 if (ReadMessages(STDIN_FILENO
,Messages
) == false)
354 // Single mode exits if the message queue is empty
355 if (Single
== true && Messages
.empty() == true)
358 string Message
= Messages
.front();
359 Messages
.erase(Messages
.begin());
361 // Fetch the message number
363 int Number
= strtol(Message
.c_str(),&End
,10);
364 if (End
== Message
.c_str())
366 cerr
<< "Malformed message!" << endl
;
373 if (Configuration(Message
) == false)
379 FetchItem
*Tmp
= new FetchItem
;
381 Tmp
->Uri
= LookupTag(Message
,"URI");
382 Tmp
->DestFile
= LookupTag(Message
,"FileName");
383 if (RFC1123StrToTime(LookupTag(Message
,"Last-Modified").c_str(),Tmp
->LastModified
) == false)
384 Tmp
->LastModified
= 0;
385 Tmp
->IndexFile
= StringToBool(LookupTag(Message
,"Index-File"),false);
386 Tmp
->FailIgnore
= StringToBool(LookupTag(Message
,"Fail-Ignore"),false);
389 // Append it to the list
390 FetchItem
**I
= &Queue
;
391 for (; *I
!= 0; I
= &(*I
)->Next
);
396 // Notify that this item is to be fetched.
397 if (Fetch(Tmp
) == false)
409 // AcqMethod::Log - Send a log message /*{{{*/
410 // ---------------------------------------------------------------------
412 void pkgAcqMethod::Log(const char *Format
,...)
414 string CurrentURI
= "<UNKNOWN>";
416 CurrentURI
= Queue
->Uri
;
419 va_start(args
,Format
);
421 // sprintf the description
423 unsigned int Len
= snprintf(S
,sizeof(S
)-4,"101 Log\n"
426 "Message: ", UsedMirror
.c_str(),
428 vsnprintf(S
+Len
,sizeof(S
)-4-Len
,Format
,args
);
431 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
435 // AcqMethod::Status - Send a status message /*{{{*/
436 // ---------------------------------------------------------------------
438 void pkgAcqMethod::Status(const char *Format
,...)
440 string CurrentURI
= "<UNKNOWN>";
442 CurrentURI
= Queue
->Uri
;
445 va_start(args
,Format
);
447 // sprintf the description
449 unsigned int Len
= snprintf(S
,sizeof(S
)-4,"102 Status\n"
452 "Message: ",UsedMirror
.c_str(),
455 vsnprintf(S
+Len
,sizeof(S
)-4-Len
,Format
,args
);
458 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
462 // AcqMethod::Redirect - Send a redirect message /*{{{*/
463 // ---------------------------------------------------------------------
464 /* This method sends the redirect message and also manipulates the queue
465 to keep the pipeline synchronized. */
466 void pkgAcqMethod::Redirect(const string
&NewURI
)
468 string CurrentURI
= "<UNKNOWN>";
470 CurrentURI
= Queue
->Uri
;
473 snprintf(S
, sizeof(S
)-50, "103 Redirect\nURI: %s\nNew-URI: %s\n\n",
474 CurrentURI
.c_str(), NewURI
.c_str());
476 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (ssize_t
)strlen(S
))
479 // Change the URI for the request.
482 /* To keep the pipeline synchronized, move the current request to
483 the end of the queue, past the end of the current pipeline. */
485 for (I
= Queue
; I
->Next
!= 0; I
= I
->Next
) ;
493 // AcqMethod::FetchResult::FetchResult - Constructor /*{{{*/
494 // ---------------------------------------------------------------------
496 pkgAcqMethod::FetchResult::FetchResult() : LastModified(0),
497 IMSHit(false), Size(0), ResumePoint(0)
501 // AcqMethod::FetchResult::TakeHashes - Load hashes /*{{{*/
502 // ---------------------------------------------------------------------
503 /* This hides the number of hashes we are supporting from the caller.
504 It just deals with the hash class. */
505 void pkgAcqMethod::FetchResult::TakeHashes(Hashes
&Hash
)
507 MD5Sum
= Hash
.MD5
.Result();
508 SHA1Sum
= Hash
.SHA1
.Result();
509 SHA256Sum
= Hash
.SHA256
.Result();