]>
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
++)
101 snprintf(S
,sizeof(S
)-50,"400 URI Failure\nURI: %s\n"
102 "Message: %s %s\n",Queue
->Uri
.c_str(),Err
.c_str(),
106 FetchItem
*Tmp
= Queue
;
109 if (Tmp
== QueueBack
)
113 snprintf(S
,sizeof(S
)-50,"400 URI Failure\nURI: <UNKNOWN>\n"
114 "Message: %s %s\n",Err
.c_str(),
117 // Set the transient flag
118 if (Transient
== true)
119 strcat(S
,"Transient-Failure: true\n\n");
123 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
127 // AcqMethod::URIStart - Indicate a download is starting /*{{{*/
128 // ---------------------------------------------------------------------
130 void pkgAcqMethod::URIStart(FetchResult
&Res
)
138 End
+= snprintf(S
,sizeof(S
),"200 URI Start\nURI: %s\n",Queue
->Uri
.c_str());
140 End
+= snprintf(End
,sizeof(S
)-4 - (End
- S
),"Size: %lu\n",Res
.Size
);
142 if (Res
.LastModified
!= 0)
143 End
+= snprintf(End
,sizeof(S
)-4 - (End
- S
),"Last-Modified: %s\n",
144 TimeRFC1123(Res
.LastModified
).c_str());
146 if (Res
.ResumePoint
!= 0)
147 End
+= snprintf(End
,sizeof(S
)-4 - (End
- S
),"Resume-Point: %lu\n",
151 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
155 // AcqMethod::URIDone - A URI is finished /*{{{*/
156 // ---------------------------------------------------------------------
158 void pkgAcqMethod::URIDone(FetchResult
&Res
, FetchResult
*Alt
)
166 End
+= snprintf(S
,sizeof(S
),"201 URI Done\nURI: %s\n",Queue
->Uri
.c_str());
168 if (Res
.Filename
.empty() == false)
169 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Filename: %s\n",Res
.Filename
.c_str());
172 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Size: %lu\n",Res
.Size
);
174 if (Res
.LastModified
!= 0)
175 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Last-Modified: %s\n",
176 TimeRFC1123(Res
.LastModified
).c_str());
178 if (Res
.MD5Sum
.empty() == false)
180 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"MD5-Hash: %s\n",Res
.MD5Sum
.c_str());
181 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"MD5Sum-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
.SHA256Sum
.empty() == false)
186 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"SHA256-Hash: %s\n",Res
.SHA256Sum
.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());
219 if (Alt
->SHA256Sum
.empty() == false)
220 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Alt-SHA256-Hash: %s\n",
221 Alt
->SHA256Sum
.c_str());
223 if (Alt
->IMSHit
== true)
224 strcat(End
,"Alt-IMS-Hit: true\n");
228 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
232 FetchItem
*Tmp
= Queue
;
235 if (Tmp
== QueueBack
)
239 // AcqMethod::MediaFail - Syncronous request for new media /*{{{*/
240 // ---------------------------------------------------------------------
241 /* This sends a 403 Media Failure message to the APT and waits for it
243 bool pkgAcqMethod::MediaFail(string Required
,string Drive
)
246 snprintf(S
,sizeof(S
),"403 Media Failure\nMedia: %s\nDrive: %s\n\n",
247 Required
.c_str(),Drive
.c_str());
249 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
252 vector
<string
> MyMessages
;
254 /* Here we read messages until we find a 603, each non 603 message is
255 appended to the main message list for later processing */
258 if (WaitFd(STDIN_FILENO
) == false)
261 if (ReadMessages(STDIN_FILENO
,MyMessages
) == false)
264 string Message
= MyMessages
.front();
265 MyMessages
.erase(MyMessages
.begin());
267 // Fetch the message number
269 int Number
= strtol(Message
.c_str(),&End
,10);
270 if (End
== Message
.c_str())
272 cerr
<< "Malformed message!" << endl
;
279 while (MyMessages
.empty() == false)
281 Messages
.push_back(MyMessages
.front());
282 MyMessages
.erase(MyMessages
.begin());
285 return !StringToBool(LookupTag(Message
,"Failed"),false);
288 Messages
.push_back(Message
);
292 // AcqMethod::Configuration - Handle the configuration message /*{{{*/
293 // ---------------------------------------------------------------------
294 /* This parses each configuration entry and puts it into the _config
295 Configuration class. */
296 bool pkgAcqMethod::Configuration(string Message
)
298 ::Configuration
&Cnf
= *_config
;
300 const char *I
= Message
.c_str();
301 const char *MsgEnd
= I
+ Message
.length();
303 unsigned int Length
= strlen("Config-Item");
304 for (; I
+ Length
< MsgEnd
; I
++)
307 if (I
[Length
] != ':' || stringcasecmp(I
,I
+Length
,"Config-Item") != 0)
312 for (; I
< MsgEnd
&& *I
== ' '; I
++);
313 const char *Equals
= I
;
314 for (; Equals
< MsgEnd
&& *Equals
!= '='; Equals
++);
315 const char *End
= Equals
;
316 for (; End
< MsgEnd
&& *End
!= '\n'; End
++);
320 Cnf
.Set(DeQuoteString(string(I
,Equals
-I
)),
321 DeQuoteString(string(Equals
+1,End
-Equals
-1)));
328 // AcqMethod::Run - Run the message engine /*{{{*/
329 // ---------------------------------------------------------------------
330 /* Fetch any messages and execute them. In single mode it returns 1 if
331 there are no more available messages - any other result is a
332 fatal failure code! */
333 int pkgAcqMethod::Run(bool Single
)
337 // Block if the message queue is empty
338 if (Messages
.empty() == true)
341 if (WaitFd(STDIN_FILENO
) == false)
343 if (ReadMessages(STDIN_FILENO
,Messages
) == false)
347 // Single mode exits if the message queue is empty
348 if (Single
== true && Messages
.empty() == true)
351 string Message
= Messages
.front();
352 Messages
.erase(Messages
.begin());
354 // Fetch the message number
356 int Number
= strtol(Message
.c_str(),&End
,10);
357 if (End
== Message
.c_str())
359 cerr
<< "Malformed message!" << endl
;
366 if (Configuration(Message
) == false)
372 FetchItem
*Tmp
= new FetchItem
;
374 Tmp
->Uri
= LookupTag(Message
,"URI");
375 Tmp
->DestFile
= LookupTag(Message
,"FileName");
376 if (StrToTime(LookupTag(Message
,"Last-Modified"),Tmp
->LastModified
) == false)
377 Tmp
->LastModified
= 0;
378 Tmp
->IndexFile
= StringToBool(LookupTag(Message
,"Index-File"),false);
381 // Append it to the list
382 FetchItem
**I
= &Queue
;
383 for (; *I
!= 0; I
= &(*I
)->Next
);
388 // Notify that this item is to be fetched.
389 if (Fetch(Tmp
) == false)
401 // AcqMethod::Log - Send a log message /*{{{*/
402 // ---------------------------------------------------------------------
404 void pkgAcqMethod::Log(const char *Format
,...)
406 string CurrentURI
= "<UNKNOWN>";
408 CurrentURI
= Queue
->Uri
;
411 va_start(args
,Format
);
413 // sprintf the description
415 unsigned int Len
= snprintf(S
,sizeof(S
)-4,"101 Log\nURI: %s\n"
416 "Message: ",CurrentURI
.c_str());
418 vsnprintf(S
+Len
,sizeof(S
)-4-Len
,Format
,args
);
421 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
425 // AcqMethod::Status - Send a status message /*{{{*/
426 // ---------------------------------------------------------------------
428 void pkgAcqMethod::Status(const char *Format
,...)
430 string CurrentURI
= "<UNKNOWN>";
432 CurrentURI
= Queue
->Uri
;
435 va_start(args
,Format
);
437 // sprintf the description
439 unsigned int Len
= snprintf(S
,sizeof(S
)-4,"102 Status\nURI: %s\n"
440 "Message: ",CurrentURI
.c_str());
442 vsnprintf(S
+Len
,sizeof(S
)-4-Len
,Format
,args
);
445 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
450 // AcqMethod::Redirect - Send a redirect message /*{{{*/
451 // ---------------------------------------------------------------------
452 /* This method sends the redirect message and also manipulates the queue
453 to keep the pipeline synchronized. */
454 void pkgAcqMethod::Redirect(const string
&NewURI
)
456 string CurrentURI
= "<UNKNOWN>";
458 CurrentURI
= Queue
->Uri
;
461 snprintf(S
, sizeof(S
)-50, "103 Redirect\nURI: %s\nNew-URI: %s\n\n",
462 CurrentURI
.c_str(), NewURI
.c_str());
464 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (ssize_t
)strlen(S
))
467 // Change the URI for the request.
470 /* To keep the pipeline synchronized, move the current request to
471 the end of the queue, past the end of the current pipeline. */
473 for (I
= Queue
; I
->Next
!= 0; I
= I
->Next
) ;
482 // AcqMethod::FetchResult::FetchResult - Constructor /*{{{*/
483 // ---------------------------------------------------------------------
485 pkgAcqMethod::FetchResult::FetchResult() : LastModified(0),
486 IMSHit(false), Size(0), ResumePoint(0)
490 // AcqMethod::FetchResult::TakeHashes - Load hashes /*{{{*/
491 // ---------------------------------------------------------------------
492 /* This hides the number of hashes we are supporting from the caller.
493 It just deals with the hash class. */
494 void pkgAcqMethod::FetchResult::TakeHashes(Hashes
&Hash
)
496 MD5Sum
= Hash
.MD5
.Result();
497 SHA1Sum
= Hash
.SHA1
.Result();
498 SHA256Sum
= Hash
.SHA256
.Result();