]>
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 /*{{{*/
19 #pragma implementation "apt-pkg/acquire-method.h"
21 #include <apt-pkg/acquire-method.h>
22 #include <apt-pkg/error.h>
23 #include <apt-pkg/configuration.h>
24 #include <apt-pkg/strutl.h>
25 #include <apt-pkg/fileutl.h>
26 #include <apt-pkg/hashes.h>
32 #include <sys/signal.h>
37 // AcqMethod::pkgAcqMethod - Constructor /*{{{*/
38 // ---------------------------------------------------------------------
39 /* This constructs the initialization text */
40 pkgAcqMethod::pkgAcqMethod(const char *Ver
,unsigned long Flags
)
44 strcat(End
,"100 Capabilities\n");
45 sprintf(End
+strlen(End
),"Version: %s\n",Ver
);
47 if ((Flags
& SingleInstance
) == SingleInstance
)
48 strcat(End
,"Single-Instance: true\n");
50 if ((Flags
& Pipeline
) == Pipeline
)
51 strcat(End
,"Pipeline: true\n");
53 if ((Flags
& SendConfig
) == SendConfig
)
54 strcat(End
,"Send-Config: true\n");
56 if ((Flags
& LocalOnly
) == LocalOnly
)
57 strcat(End
,"Local-Only: true\n");
59 if ((Flags
& NeedsCleanup
) == NeedsCleanup
)
60 strcat(End
,"Needs-Cleanup: true\n");
62 if ((Flags
& Removable
) == Removable
)
63 strcat(End
,"Removable: true\n");
66 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
69 SetNonBlock(STDIN_FILENO
,true);
75 // AcqMethod::Fail - A fetch has failed /*{{{*/
76 // ---------------------------------------------------------------------
78 void pkgAcqMethod::Fail(bool Transient
)
80 string Err
= "Undetermined Error";
81 if (_error
->empty() == false)
82 _error
->PopMessage(Err
);
87 // AcqMethod::Fail - A fetch has failed /*{{{*/
88 // ---------------------------------------------------------------------
90 void pkgAcqMethod::Fail(string Err
,bool Transient
)
92 // Strip out junk from the error messages
93 for (string::iterator I
= Err
.begin(); I
!= Err
.end(); I
++)
104 snprintf(S
,sizeof(S
)-50,"400 URI Failure\nURI: %s\n"
105 "Message: %s %s\n",Queue
->Uri
.c_str(),Err
.c_str(),
109 FetchItem
*Tmp
= Queue
;
112 if (Tmp
== QueueBack
)
116 snprintf(S
,sizeof(S
)-50,"400 URI Failure\nURI: <UNKNOWN>\n"
117 "Message: %s %s\n",Err
.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",
154 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
158 // AcqMethod::URIDone - A URI is finished /*{{{*/
159 // ---------------------------------------------------------------------
161 void pkgAcqMethod::URIDone(FetchResult
&Res
, FetchResult
*Alt
)
169 End
+= snprintf(S
,sizeof(S
),"201 URI Done\nURI: %s\n",Queue
->Uri
.c_str());
171 if (Res
.Filename
.empty() == false)
172 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Filename: %s\n",Res
.Filename
.c_str());
175 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Size: %lu\n",Res
.Size
);
177 if (Res
.LastModified
!= 0)
178 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Last-Modified: %s\n",
179 TimeRFC1123(Res
.LastModified
).c_str());
181 if (Res
.MD5Sum
.empty() == false)
182 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"MD5-Hash: %s\n",Res
.MD5Sum
.c_str());
183 if (Res
.SHA1Sum
.empty() == false)
184 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"SHA1-Hash: %s\n",Res
.SHA1Sum
.c_str());
185 if (Res
.GPGVOutput
.size() > 0)
186 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"GPGVOutput:\n");
187 for (vector
<string
>::iterator I
= Res
.GPGVOutput
.begin();
188 I
!= Res
.GPGVOutput
.end(); I
++)
189 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
), " %s\n", (*I
).c_str());
191 if (Res
.ResumePoint
!= 0)
192 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Resume-Point: %lu\n",
195 if (Res
.IMSHit
== true)
196 strcat(End
,"IMS-Hit: true\n");
201 if (Alt
->Filename
.empty() == false)
202 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Alt-Filename: %s\n",Alt
->Filename
.c_str());
205 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Alt-Size: %lu\n",Alt
->Size
);
207 if (Alt
->LastModified
!= 0)
208 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Alt-Last-Modified: %s\n",
209 TimeRFC1123(Alt
->LastModified
).c_str());
211 if (Alt
->MD5Sum
.empty() == false)
212 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Alt-MD5-Hash: %s\n",
213 Alt
->MD5Sum
.c_str());
214 if (Alt
->SHA1Sum
.empty() == false)
215 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Alt-SHA1-Hash: %s\n",
216 Alt
->SHA1Sum
.c_str());
218 if (Alt
->IMSHit
== true)
219 strcat(End
,"Alt-IMS-Hit: true\n");
223 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
227 FetchItem
*Tmp
= Queue
;
230 if (Tmp
== QueueBack
)
234 // AcqMethod::MediaFail - Syncronous request for new media /*{{{*/
235 // ---------------------------------------------------------------------
236 /* This sends a 403 Media Failure message to the APT and waits for it
238 bool pkgAcqMethod::MediaFail(string Required
,string Drive
)
241 snprintf(S
,sizeof(S
),"403 Media Failure\nMedia: %s\nDrive: %s\n\n",
242 Required
.c_str(),Drive
.c_str());
244 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
247 vector
<string
> MyMessages
;
249 /* Here we read messages until we find a 603, each non 603 message is
250 appended to the main message list for later processing */
253 if (WaitFd(STDIN_FILENO
) == false)
256 if (ReadMessages(STDIN_FILENO
,MyMessages
) == false)
259 string Message
= MyMessages
.front();
260 MyMessages
.erase(MyMessages
.begin());
262 // Fetch the message number
264 int Number
= strtol(Message
.c_str(),&End
,10);
265 if (End
== Message
.c_str())
267 cerr
<< "Malformed message!" << endl
;
274 while (MyMessages
.empty() == false)
276 Messages
.push_back(MyMessages
.front());
277 MyMessages
.erase(MyMessages
.begin());
280 return !StringToBool(LookupTag(Message
,"Failed"),false);
283 Messages
.push_back(Message
);
287 // AcqMethod::Configuration - Handle the configuration message /*{{{*/
288 // ---------------------------------------------------------------------
289 /* This parses each configuration entry and puts it into the _config
290 Configuration class. */
291 bool pkgAcqMethod::Configuration(string Message
)
293 ::Configuration
&Cnf
= *_config
;
295 const char *I
= Message
.c_str();
296 const char *MsgEnd
= I
+ Message
.length();
298 unsigned int Length
= strlen("Config-Item");
299 for (; I
+ Length
< MsgEnd
; I
++)
302 if (I
[Length
] != ':' || stringcasecmp(I
,I
+Length
,"Config-Item") != 0)
307 for (; I
< MsgEnd
&& *I
== ' '; I
++);
308 const char *Equals
= I
;
309 for (; Equals
< MsgEnd
&& *Equals
!= '='; Equals
++);
310 const char *End
= Equals
;
311 for (; End
< MsgEnd
&& *End
!= '\n'; End
++);
315 Cnf
.Set(DeQuoteString(string(I
,Equals
-I
)),
316 DeQuoteString(string(Equals
+1,End
-Equals
-1)));
323 // AcqMethod::Run - Run the message engine /*{{{*/
324 // ---------------------------------------------------------------------
325 /* Fetch any messages and execute them. In single mode it returns 1 if
326 there are no more available messages - any other result is a
327 fatal failure code! */
328 int pkgAcqMethod::Run(bool Single
)
332 // Block if the message queue is empty
333 if (Messages
.empty() == true)
336 if (WaitFd(STDIN_FILENO
) == false)
338 if (ReadMessages(STDIN_FILENO
,Messages
) == false)
342 // Single mode exits if the message queue is empty
343 if (Single
== true && Messages
.empty() == true)
346 string Message
= Messages
.front();
347 Messages
.erase(Messages
.begin());
349 // Fetch the message number
351 int Number
= strtol(Message
.c_str(),&End
,10);
352 if (End
== Message
.c_str())
354 cerr
<< "Malformed message!" << endl
;
361 if (Configuration(Message
) == false)
367 FetchItem
*Tmp
= new FetchItem
;
369 Tmp
->Uri
= LookupTag(Message
,"URI");
370 Tmp
->DestFile
= LookupTag(Message
,"FileName");
371 Tmp
->ExpectedMD5
= LookupTag(Message
,"ExpectedMD5");
372 if (StrToTime(LookupTag(Message
,"Last-Modified"),Tmp
->LastModified
) == false)
373 Tmp
->LastModified
= 0;
374 Tmp
->IndexFile
= StringToBool(LookupTag(Message
,"Index-File"),false);
377 // Append it to the list
378 FetchItem
**I
= &Queue
;
379 for (; *I
!= 0; I
= &(*I
)->Next
);
384 // Notify that this item is to be fetched.
385 if (Fetch(Tmp
) == false)
397 // AcqMethod::Log - Send a log message /*{{{*/
398 // ---------------------------------------------------------------------
400 void pkgAcqMethod::Log(const char *Format
,...)
402 string CurrentURI
= "<UNKNOWN>";
404 CurrentURI
= Queue
->Uri
;
407 va_start(args
,Format
);
409 // sprintf the description
411 unsigned int Len
= snprintf(S
,sizeof(S
)-4,"101 Log\nURI: %s\n"
412 "Message: ",CurrentURI
.c_str());
414 vsnprintf(S
+Len
,sizeof(S
)-4-Len
,Format
,args
);
417 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
421 // AcqMethod::Status - Send a status message /*{{{*/
422 // ---------------------------------------------------------------------
424 void pkgAcqMethod::Status(const char *Format
,...)
426 string CurrentURI
= "<UNKNOWN>";
428 CurrentURI
= Queue
->Uri
;
431 va_start(args
,Format
);
433 // sprintf the description
435 unsigned int Len
= snprintf(S
,sizeof(S
)-4,"102 Status\nURI: %s\n"
436 "Message: ",CurrentURI
.c_str());
438 vsnprintf(S
+Len
,sizeof(S
)-4-Len
,Format
,args
);
441 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
446 // AcqMethod::FetchResult::FetchResult - Constructor /*{{{*/
447 // ---------------------------------------------------------------------
449 pkgAcqMethod::FetchResult::FetchResult() : LastModified(0),
450 IMSHit(false), Size(0), ResumePoint(0)
454 // AcqMethod::FetchResult::TakeHashes - Load hashes /*{{{*/
455 // ---------------------------------------------------------------------
456 /* This hides the number of hashes we are supporting from the caller.
457 It just deals with the hash class. */
458 void pkgAcqMethod::FetchResult::TakeHashes(Hashes
&Hash
)
460 MD5Sum
= Hash
.MD5
.Result();
461 SHA1Sum
= Hash
.SHA1
.Result();