]>
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",
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 (UsedMirror
.empty() == false)
186 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"UsedMirror: %s\n",UsedMirror
.c_str());
187 if (Res
.GPGVOutput
.size() > 0)
188 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"GPGVOutput:\n");
189 for (vector
<string
>::iterator I
= Res
.GPGVOutput
.begin();
190 I
!= Res
.GPGVOutput
.end(); I
++)
191 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
), " %s\n", (*I
).c_str());
193 if (Res
.ResumePoint
!= 0)
194 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Resume-Point: %lu\n",
197 if (Res
.IMSHit
== true)
198 strcat(End
,"IMS-Hit: true\n");
203 if (Alt
->Filename
.empty() == false)
204 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Alt-Filename: %s\n",Alt
->Filename
.c_str());
207 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Alt-Size: %lu\n",Alt
->Size
);
209 if (Alt
->LastModified
!= 0)
210 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Alt-Last-Modified: %s\n",
211 TimeRFC1123(Alt
->LastModified
).c_str());
213 if (Alt
->MD5Sum
.empty() == false)
214 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Alt-MD5-Hash: %s\n",
215 Alt
->MD5Sum
.c_str());
216 if (Alt
->SHA1Sum
.empty() == false)
217 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Alt-SHA1-Hash: %s\n",
218 Alt
->SHA1Sum
.c_str());
220 if (Alt
->IMSHit
== true)
221 strcat(End
,"Alt-IMS-Hit: true\n");
225 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
229 FetchItem
*Tmp
= Queue
;
232 if (Tmp
== QueueBack
)
236 // AcqMethod::MediaFail - Syncronous request for new media /*{{{*/
237 // ---------------------------------------------------------------------
238 /* This sends a 403 Media Failure message to the APT and waits for it
240 bool pkgAcqMethod::MediaFail(string Required
,string Drive
)
243 snprintf(S
,sizeof(S
),"403 Media Failure\nMedia: %s\nDrive: %s\n\n",
244 Required
.c_str(),Drive
.c_str());
246 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
249 vector
<string
> MyMessages
;
251 /* Here we read messages until we find a 603, each non 603 message is
252 appended to the main message list for later processing */
255 if (WaitFd(STDIN_FILENO
) == false)
258 if (ReadMessages(STDIN_FILENO
,MyMessages
) == false)
261 string Message
= MyMessages
.front();
262 MyMessages
.erase(MyMessages
.begin());
264 // Fetch the message number
266 int Number
= strtol(Message
.c_str(),&End
,10);
267 if (End
== Message
.c_str())
269 cerr
<< "Malformed message!" << endl
;
276 while (MyMessages
.empty() == false)
278 Messages
.push_back(MyMessages
.front());
279 MyMessages
.erase(MyMessages
.begin());
282 return !StringToBool(LookupTag(Message
,"Failed"),false);
285 Messages
.push_back(Message
);
289 // AcqMethod::Configuration - Handle the configuration message /*{{{*/
290 // ---------------------------------------------------------------------
291 /* This parses each configuration entry and puts it into the _config
292 Configuration class. */
293 bool pkgAcqMethod::Configuration(string Message
)
295 ::Configuration
&Cnf
= *_config
;
297 const char *I
= Message
.c_str();
298 const char *MsgEnd
= I
+ Message
.length();
300 unsigned int Length
= strlen("Config-Item");
301 for (; I
+ Length
< MsgEnd
; I
++)
304 if (I
[Length
] != ':' || stringcasecmp(I
,I
+Length
,"Config-Item") != 0)
309 for (; I
< MsgEnd
&& *I
== ' '; I
++);
310 const char *Equals
= I
;
311 for (; Equals
< MsgEnd
&& *Equals
!= '='; Equals
++);
312 const char *End
= Equals
;
313 for (; End
< MsgEnd
&& *End
!= '\n'; End
++);
317 Cnf
.Set(DeQuoteString(string(I
,Equals
-I
)),
318 DeQuoteString(string(Equals
+1,End
-Equals
-1)));
325 // AcqMethod::Run - Run the message engine /*{{{*/
326 // ---------------------------------------------------------------------
327 /* Fetch any messages and execute them. In single mode it returns 1 if
328 there are no more available messages - any other result is a
329 fatal failure code! */
330 int pkgAcqMethod::Run(bool Single
)
334 // Block if the message queue is empty
335 if (Messages
.empty() == true)
338 if (WaitFd(STDIN_FILENO
) == false)
340 if (ReadMessages(STDIN_FILENO
,Messages
) == false)
344 // Single mode exits if the message queue is empty
345 if (Single
== true && Messages
.empty() == true)
348 string Message
= Messages
.front();
349 Messages
.erase(Messages
.begin());
351 // Fetch the message number
353 int Number
= strtol(Message
.c_str(),&End
,10);
354 if (End
== Message
.c_str())
356 cerr
<< "Malformed message!" << endl
;
363 if (Configuration(Message
) == false)
369 FetchItem
*Tmp
= new FetchItem
;
371 Tmp
->Uri
= LookupTag(Message
,"URI");
372 Tmp
->DestFile
= LookupTag(Message
,"FileName");
373 if (StrToTime(LookupTag(Message
,"Last-Modified"),Tmp
->LastModified
) == false)
374 Tmp
->LastModified
= 0;
375 Tmp
->IndexFile
= StringToBool(LookupTag(Message
,"Index-File"),false);
378 // Append it to the list
379 FetchItem
**I
= &Queue
;
380 for (; *I
!= 0; I
= &(*I
)->Next
);
385 // Notify that this item is to be fetched.
386 if (Fetch(Tmp
) == false)
398 // AcqMethod::Log - Send a log message /*{{{*/
399 // ---------------------------------------------------------------------
401 void pkgAcqMethod::Log(const char *Format
,...)
403 string CurrentURI
= "<UNKNOWN>";
405 CurrentURI
= Queue
->Uri
;
408 va_start(args
,Format
);
410 // sprintf the description
412 unsigned int Len
= snprintf(S
,sizeof(S
)-4,"101 Log\nURI: %s\n"
413 "Message: ",CurrentURI
.c_str());
415 vsnprintf(S
+Len
,sizeof(S
)-4-Len
,Format
,args
);
418 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
422 // AcqMethod::Status - Send a status message /*{{{*/
423 // ---------------------------------------------------------------------
425 void pkgAcqMethod::Status(const char *Format
,...)
427 string CurrentURI
= "<UNKNOWN>";
429 CurrentURI
= Queue
->Uri
;
432 va_start(args
,Format
);
434 // sprintf the description
436 unsigned int Len
= snprintf(S
,sizeof(S
)-4,"102 Status\nURI: %s\n"
437 "Message: ",CurrentURI
.c_str());
439 vsnprintf(S
+Len
,sizeof(S
)-4-Len
,Format
,args
);
442 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
447 // AcqMethod::FetchResult::FetchResult - Constructor /*{{{*/
448 // ---------------------------------------------------------------------
450 pkgAcqMethod::FetchResult::FetchResult() : LastModified(0),
451 IMSHit(false), Size(0), ResumePoint(0)
455 // AcqMethod::FetchResult::TakeHashes - Load hashes /*{{{*/
456 // ---------------------------------------------------------------------
457 /* This hides the number of hashes we are supporting from the caller.
458 It just deals with the hash class. */
459 void pkgAcqMethod::FetchResult::TakeHashes(Hashes
&Hash
)
461 MD5Sum
= Hash
.MD5
.Result();
462 SHA1Sum
= Hash
.SHA1
.Result();