]>
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)
183 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"MD5-Hash: %s\n",Res
.MD5Sum
.c_str());
184 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"MD5Sum-Hash: %s\n",Res
.MD5Sum
.c_str());
186 if (Res
.SHA1Sum
.empty() == false)
187 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"SHA1-Hash: %s\n",Res
.SHA1Sum
.c_str());
188 if (Res
.SHA256Sum
.empty() == false)
189 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"SHA256-Hash: %s\n",Res
.SHA256Sum
.c_str());
190 if (UsedMirror
.empty() == false)
191 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"UsedMirror: %s\n",UsedMirror
.c_str());
192 if (Res
.GPGVOutput
.size() > 0)
193 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"GPGVOutput:\n");
194 for (vector
<string
>::iterator I
= Res
.GPGVOutput
.begin();
195 I
!= Res
.GPGVOutput
.end(); I
++)
196 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
), " %s\n", (*I
).c_str());
198 if (Res
.ResumePoint
!= 0)
199 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Resume-Point: %lu\n",
202 if (Res
.IMSHit
== true)
203 strcat(End
,"IMS-Hit: true\n");
208 if (Alt
->Filename
.empty() == false)
209 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Alt-Filename: %s\n",Alt
->Filename
.c_str());
212 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Alt-Size: %lu\n",Alt
->Size
);
214 if (Alt
->LastModified
!= 0)
215 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Alt-Last-Modified: %s\n",
216 TimeRFC1123(Alt
->LastModified
).c_str());
218 if (Alt
->MD5Sum
.empty() == false)
219 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Alt-MD5-Hash: %s\n",
220 Alt
->MD5Sum
.c_str());
221 if (Alt
->SHA1Sum
.empty() == false)
222 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Alt-SHA1-Hash: %s\n",
223 Alt
->SHA1Sum
.c_str());
224 if (Alt
->SHA256Sum
.empty() == false)
225 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Alt-SHA256-Hash: %s\n",
226 Alt
->SHA256Sum
.c_str());
228 if (Alt
->IMSHit
== true)
229 strcat(End
,"Alt-IMS-Hit: true\n");
233 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
237 FetchItem
*Tmp
= Queue
;
240 if (Tmp
== QueueBack
)
244 // AcqMethod::MediaFail - Syncronous request for new media /*{{{*/
245 // ---------------------------------------------------------------------
246 /* This sends a 403 Media Failure message to the APT and waits for it
248 bool pkgAcqMethod::MediaFail(string Required
,string Drive
)
251 snprintf(S
,sizeof(S
),"403 Media Failure\nMedia: %s\nDrive: %s\n\n",
252 Required
.c_str(),Drive
.c_str());
254 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
257 vector
<string
> MyMessages
;
259 /* Here we read messages until we find a 603, each non 603 message is
260 appended to the main message list for later processing */
263 if (WaitFd(STDIN_FILENO
) == false)
266 if (ReadMessages(STDIN_FILENO
,MyMessages
) == false)
269 string Message
= MyMessages
.front();
270 MyMessages
.erase(MyMessages
.begin());
272 // Fetch the message number
274 int Number
= strtol(Message
.c_str(),&End
,10);
275 if (End
== Message
.c_str())
277 cerr
<< "Malformed message!" << endl
;
284 while (MyMessages
.empty() == false)
286 Messages
.push_back(MyMessages
.front());
287 MyMessages
.erase(MyMessages
.begin());
290 return !StringToBool(LookupTag(Message
,"Failed"),false);
293 Messages
.push_back(Message
);
297 // AcqMethod::Configuration - Handle the configuration message /*{{{*/
298 // ---------------------------------------------------------------------
299 /* This parses each configuration entry and puts it into the _config
300 Configuration class. */
301 bool pkgAcqMethod::Configuration(string Message
)
303 ::Configuration
&Cnf
= *_config
;
305 const char *I
= Message
.c_str();
306 const char *MsgEnd
= I
+ Message
.length();
308 unsigned int Length
= strlen("Config-Item");
309 for (; I
+ Length
< MsgEnd
; I
++)
312 if (I
[Length
] != ':' || stringcasecmp(I
,I
+Length
,"Config-Item") != 0)
317 for (; I
< MsgEnd
&& *I
== ' '; I
++);
318 const char *Equals
= I
;
319 for (; Equals
< MsgEnd
&& *Equals
!= '='; Equals
++);
320 const char *End
= Equals
;
321 for (; End
< MsgEnd
&& *End
!= '\n'; End
++);
325 Cnf
.Set(DeQuoteString(string(I
,Equals
-I
)),
326 DeQuoteString(string(Equals
+1,End
-Equals
-1)));
333 // AcqMethod::Run - Run the message engine /*{{{*/
334 // ---------------------------------------------------------------------
335 /* Fetch any messages and execute them. In single mode it returns 1 if
336 there are no more available messages - any other result is a
337 fatal failure code! */
338 int pkgAcqMethod::Run(bool Single
)
342 // Block if the message queue is empty
343 if (Messages
.empty() == true)
346 if (WaitFd(STDIN_FILENO
) == false)
348 if (ReadMessages(STDIN_FILENO
,Messages
) == false)
352 // Single mode exits if the message queue is empty
353 if (Single
== true && Messages
.empty() == true)
356 string Message
= Messages
.front();
357 Messages
.erase(Messages
.begin());
359 // Fetch the message number
361 int Number
= strtol(Message
.c_str(),&End
,10);
362 if (End
== Message
.c_str())
364 cerr
<< "Malformed message!" << endl
;
371 if (Configuration(Message
) == false)
377 FetchItem
*Tmp
= new FetchItem
;
379 Tmp
->Uri
= LookupTag(Message
,"URI");
380 Tmp
->DestFile
= LookupTag(Message
,"FileName");
381 if (StrToTime(LookupTag(Message
,"Last-Modified"),Tmp
->LastModified
) == false)
382 Tmp
->LastModified
= 0;
383 Tmp
->IndexFile
= StringToBool(LookupTag(Message
,"Index-File"),false);
386 // Append it to the list
387 FetchItem
**I
= &Queue
;
388 for (; *I
!= 0; I
= &(*I
)->Next
);
393 // Notify that this item is to be fetched.
394 if (Fetch(Tmp
) == false)
406 // AcqMethod::Log - Send a log message /*{{{*/
407 // ---------------------------------------------------------------------
409 void pkgAcqMethod::Log(const char *Format
,...)
411 string CurrentURI
= "<UNKNOWN>";
413 CurrentURI
= Queue
->Uri
;
416 va_start(args
,Format
);
418 // sprintf the description
420 unsigned int Len
= snprintf(S
,sizeof(S
)-4,"101 Log\nURI: %s\n"
421 "Message: ",CurrentURI
.c_str());
423 vsnprintf(S
+Len
,sizeof(S
)-4-Len
,Format
,args
);
426 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
430 // AcqMethod::Status - Send a status message /*{{{*/
431 // ---------------------------------------------------------------------
433 void pkgAcqMethod::Status(const char *Format
,...)
435 string CurrentURI
= "<UNKNOWN>";
437 CurrentURI
= Queue
->Uri
;
440 va_start(args
,Format
);
442 // sprintf the description
444 unsigned int Len
= snprintf(S
,sizeof(S
)-4,"102 Status\nURI: %s\n"
445 "Message: ",CurrentURI
.c_str());
447 vsnprintf(S
+Len
,sizeof(S
)-4-Len
,Format
,args
);
450 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
454 // AcqMethod::Redirect - Send a redirect message /*{{{*/
455 // ---------------------------------------------------------------------
456 /* This method sends the redirect message and also manipulates the queue
457 to keep the pipeline synchronized. */
458 void pkgAcqMethod::Redirect(const string
&NewURI
)
460 string CurrentURI
= "<UNKNOWN>";
462 CurrentURI
= Queue
->Uri
;
465 snprintf(S
, sizeof(S
)-50, "103 Redirect\nURI: %s\nNew-URI: %s\n\n",
466 CurrentURI
.c_str(), NewURI
.c_str());
468 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (ssize_t
)strlen(S
))
471 // Change the URI for the request.
474 /* To keep the pipeline synchronized, move the current request to
475 the end of the queue, past the end of the current pipeline. */
477 for (I
= Queue
; I
->Next
!= 0; I
= I
->Next
) ;
485 // AcqMethod::FetchResult::FetchResult - Constructor /*{{{*/
486 // ---------------------------------------------------------------------
488 pkgAcqMethod::FetchResult::FetchResult() : LastModified(0),
489 IMSHit(false), Size(0), ResumePoint(0)
493 // AcqMethod::FetchResult::TakeHashes - Load hashes /*{{{*/
494 // ---------------------------------------------------------------------
495 /* This hides the number of hashes we are supporting from the caller.
496 It just deals with the hash class. */
497 void pkgAcqMethod::FetchResult::TakeHashes(Hashes
&Hash
)
499 MD5Sum
= Hash
.MD5
.Result();
500 SHA1Sum
= Hash
.SHA1
.Result();
501 SHA256Sum
= Hash
.SHA256
.Result();