]>
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)
179 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"MD5-Hash: %s\n",Res
.MD5Sum
.c_str());
180 if (Res
.SHA1Sum
.empty() == false)
181 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"SHA1-Hash: %s\n",Res
.SHA1Sum
.c_str());
182 if (Res
.GPGVOutput
.size() > 0)
183 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"GPGVOutput:\n");
184 for (vector
<string
>::iterator I
= Res
.GPGVOutput
.begin();
185 I
!= Res
.GPGVOutput
.end(); I
++)
186 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
), " %s\n", (*I
).c_str());
188 if (Res
.ResumePoint
!= 0)
189 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Resume-Point: %lu\n",
192 if (Res
.IMSHit
== true)
193 strcat(End
,"IMS-Hit: true\n");
198 if (Alt
->Filename
.empty() == false)
199 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Alt-Filename: %s\n",Alt
->Filename
.c_str());
202 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Alt-Size: %lu\n",Alt
->Size
);
204 if (Alt
->LastModified
!= 0)
205 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Alt-Last-Modified: %s\n",
206 TimeRFC1123(Alt
->LastModified
).c_str());
208 if (Alt
->MD5Sum
.empty() == false)
209 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Alt-MD5-Hash: %s\n",
210 Alt
->MD5Sum
.c_str());
211 if (Alt
->SHA1Sum
.empty() == false)
212 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Alt-SHA1-Hash: %s\n",
213 Alt
->SHA1Sum
.c_str());
215 if (Alt
->IMSHit
== true)
216 strcat(End
,"Alt-IMS-Hit: true\n");
220 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
224 FetchItem
*Tmp
= Queue
;
227 if (Tmp
== QueueBack
)
231 // AcqMethod::MediaFail - Syncronous request for new media /*{{{*/
232 // ---------------------------------------------------------------------
233 /* This sends a 403 Media Failure message to the APT and waits for it
235 bool pkgAcqMethod::MediaFail(string Required
,string Drive
)
238 snprintf(S
,sizeof(S
),"403 Media Failure\nMedia: %s\nDrive: %s\n\n",
239 Required
.c_str(),Drive
.c_str());
241 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
244 vector
<string
> MyMessages
;
246 /* Here we read messages until we find a 603, each non 603 message is
247 appended to the main message list for later processing */
250 if (WaitFd(STDIN_FILENO
) == false)
253 if (ReadMessages(STDIN_FILENO
,MyMessages
) == false)
256 string Message
= MyMessages
.front();
257 MyMessages
.erase(MyMessages
.begin());
259 // Fetch the message number
261 int Number
= strtol(Message
.c_str(),&End
,10);
262 if (End
== Message
.c_str())
264 cerr
<< "Malformed message!" << endl
;
271 while (MyMessages
.empty() == false)
273 Messages
.push_back(MyMessages
.front());
274 MyMessages
.erase(MyMessages
.begin());
277 return !StringToBool(LookupTag(Message
,"Failed"),false);
280 Messages
.push_back(Message
);
284 // AcqMethod::Configuration - Handle the configuration message /*{{{*/
285 // ---------------------------------------------------------------------
286 /* This parses each configuration entry and puts it into the _config
287 Configuration class. */
288 bool pkgAcqMethod::Configuration(string Message
)
290 ::Configuration
&Cnf
= *_config
;
292 const char *I
= Message
.c_str();
293 const char *MsgEnd
= I
+ Message
.length();
295 unsigned int Length
= strlen("Config-Item");
296 for (; I
+ Length
< MsgEnd
; I
++)
299 if (I
[Length
] != ':' || stringcasecmp(I
,I
+Length
,"Config-Item") != 0)
304 for (; I
< MsgEnd
&& *I
== ' '; I
++);
305 const char *Equals
= I
;
306 for (; Equals
< MsgEnd
&& *Equals
!= '='; Equals
++);
307 const char *End
= Equals
;
308 for (; End
< MsgEnd
&& *End
!= '\n'; End
++);
312 Cnf
.Set(DeQuoteString(string(I
,Equals
-I
)),
313 DeQuoteString(string(Equals
+1,End
-Equals
-1)));
320 // AcqMethod::Run - Run the message engine /*{{{*/
321 // ---------------------------------------------------------------------
322 /* Fetch any messages and execute them. In single mode it returns 1 if
323 there are no more available messages - any other result is a
324 fatal failure code! */
325 int pkgAcqMethod::Run(bool Single
)
329 // Block if the message queue is empty
330 if (Messages
.empty() == true)
333 if (WaitFd(STDIN_FILENO
) == false)
335 if (ReadMessages(STDIN_FILENO
,Messages
) == false)
339 // Single mode exits if the message queue is empty
340 if (Single
== true && Messages
.empty() == true)
343 string Message
= Messages
.front();
344 Messages
.erase(Messages
.begin());
346 // Fetch the message number
348 int Number
= strtol(Message
.c_str(),&End
,10);
349 if (End
== Message
.c_str())
351 cerr
<< "Malformed message!" << endl
;
358 if (Configuration(Message
) == false)
364 FetchItem
*Tmp
= new FetchItem
;
366 Tmp
->Uri
= LookupTag(Message
,"URI");
367 Tmp
->DestFile
= LookupTag(Message
,"FileName");
368 if (StrToTime(LookupTag(Message
,"Last-Modified"),Tmp
->LastModified
) == false)
369 Tmp
->LastModified
= 0;
370 Tmp
->IndexFile
= StringToBool(LookupTag(Message
,"Index-File"),false);
373 // Append it to the list
374 FetchItem
**I
= &Queue
;
375 for (; *I
!= 0; I
= &(*I
)->Next
);
380 // Notify that this item is to be fetched.
381 if (Fetch(Tmp
) == false)
393 // AcqMethod::Log - Send a log message /*{{{*/
394 // ---------------------------------------------------------------------
396 void pkgAcqMethod::Log(const char *Format
,...)
398 string CurrentURI
= "<UNKNOWN>";
400 CurrentURI
= Queue
->Uri
;
403 va_start(args
,Format
);
405 // sprintf the description
407 unsigned int Len
= snprintf(S
,sizeof(S
)-4,"101 Log\nURI: %s\n"
408 "Message: ",CurrentURI
.c_str());
410 vsnprintf(S
+Len
,sizeof(S
)-4-Len
,Format
,args
);
413 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
417 // AcqMethod::Status - Send a status message /*{{{*/
418 // ---------------------------------------------------------------------
420 void pkgAcqMethod::Status(const char *Format
,...)
422 string CurrentURI
= "<UNKNOWN>";
424 CurrentURI
= Queue
->Uri
;
427 va_start(args
,Format
);
429 // sprintf the description
431 unsigned int Len
= snprintf(S
,sizeof(S
)-4,"102 Status\nURI: %s\n"
432 "Message: ",CurrentURI
.c_str());
434 vsnprintf(S
+Len
,sizeof(S
)-4-Len
,Format
,args
);
437 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
442 // AcqMethod::FetchResult::FetchResult - Constructor /*{{{*/
443 // ---------------------------------------------------------------------
445 pkgAcqMethod::FetchResult::FetchResult() : LastModified(0),
446 IMSHit(false), Size(0), ResumePoint(0)
450 // AcqMethod::FetchResult::TakeHashes - Load hashes /*{{{*/
451 // ---------------------------------------------------------------------
452 /* This hides the number of hashes we are supporting from the caller.
453 It just deals with the hash class. */
454 void pkgAcqMethod::FetchResult::TakeHashes(Hashes
&Hash
)
456 MD5Sum
= Hash
.MD5
.Result();
457 SHA1Sum
= Hash
.SHA1
.Result();