--- /dev/null
+NOTE: The ChangeLog generator will parse for names and email addresses. The
+'CVS:<name>' tag should indicate who this pair refers to.
+
+The project hierachy stands at:
+
+CVS:bcwhite Brian White <bcwhite@verisim.com>
+- Project Leader
+- General organization, dispute resolution, final say on "capabilities"
+
+CVS:jgg Jason Gunthorpe <jgg@gpu.srv.ualberta.ca>
+- Chief Programmer
+- Code organization, task breakdown, final say on "code"
+
+CVS:tom Tom Lees <tom@lpsg.demon.co.uk>
+- Dpkg Consultant
+- Make system
+- Expert on compatibility with existing dpkg, dependency algorithms, etc.
+
+CVS:srivasta Manoj Srivastava <srivasta@datasync.com>
+- Dependency Expert
+
+CVS:behanw Behan Webster <behanw@verisim.com>
+- Chief Designer
+- Screen layout, ease of use, final say on "user interface"
+
+CVS:che Ben Gertzfield <che@debian.org>
+- Documentation
+
+CVS:branden Branden Robinson <branden@purdue.edu>
+- Man Page Documentation
+
+CVS:scott Scott Ellis <storm@gate.net>
+- .deb archive creater
+
+CVS:doogie Adam Heath <doogie@debian.org>
+- FTP method author
\ No newline at end of file
# This is the top level make file for APT, it recurses to each lower
# level make file and runs it with the proper target
+ifndef NOISY
.SILENT:
+endif
.PHONY: headers library clean veryclean all binary program doc
all headers library clean veryclean binary program doc:
.PHONY: maintainer-clean dist-clean distclean pristine sanity
maintainer-clean dist-clean distclean pristine sanity: veryclean
+
+
+# The startup target builds the necessary configure scripts. It should
+# be used after a CVS checkout.
+.PHONY: startup
+startup: configure
+
+configure: aclocal.m4 configure.in
+ autoconf
+
+aclocal.m4:
+ aclocal -I buildlib
Only .o and .d files are placed in the obj/ subdirectory. The final compiled
binaries are placed in bin, published headers for inter-component linking
are placed in include/ and documentation is generated into doc/. This means
-all runnable programs are within the bin/ directory a huge benifit for
+all runnable programs are within the bin/ directory, a huge benifit for
debugging inter-program relationships. The .so files are also placed in
bin/ for simplicity.
+By default make is put into silent mode. During operation there should be
+no shell or compiler messages only status messages from the makefiles,
+if any pop up that indicates there may be a problem with your environment.
+For debugging you can disable this by setting NOISY=1, ala
+ make NOISY=1
+
Using the makefiles
~~~~~ ~~~ ~~~~~~~~~
The makefiles for the components are really simple. The complexity is hidden
described in the fragment code in buildlib. Some tips on writing fragments
are included in buildlib/defaults.mak
-Jason
+The fragments are NEVER processed by configure, so if you make changes to
+them they will have an immediate effect.
+
+Autoconf
+~~~~~~~~
+Straight out of CVS you have to initialize autoconf. This requires
+automake (I really don't know why) and autoconf and requires doing
+ aclocal -I buidlib
+ autoconf
+
+Autoconf is configured to do some basic system probes for optional and
+required functionality and generate an environment.mak and include/config.h
+from it's findings. It will then write a 'makefile' and run make dirs to
+create the output directory tree.
+
+It is not my belief that autoconf should be used to generate substantial
+source code markup to escape OS problems. If an OS problem does crop up
+it can likely be corrected by installing the correct files into the
+build include/ dir and perhaps writing some replacement code and
+linking it in. To the fullest extent possible the source code should conform
+to standards and not cater to broken systems.
+
+Autoconf will also wite a makefile into the top level of the build dir,
+this simply acts as a wrapper to the main top level make in the source tree.
+There is one big warning, you can't use both this make file and the
+ones in the top level tree. Make is not able to resolve rules that
+go to the same file through different paths and this will confuse the
+depends mechanism. I recommend always using the makefiles in the
+source directory and exporting BUILD
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: acquire-item.cc,v 1.5 1998/10/26 07:11:43 jgg Exp $
+// $Id: acquire-item.cc,v 1.6 1998/10/30 07:53:34 jgg Exp $
/* ######################################################################
Acquire Item - Item to acquire
/*}}}*/
// Acquire::Item::Failed - Item failed to download /*{{{*/
// ---------------------------------------------------------------------
-/* */
+/* We return to an idle state if there are still other queues that could
+ fetch this object */
void pkgAcquire::Item::Failed(string Message)
{
- Status = StatError;
- ErrorText = LookupTag(Message,"Message");
+ Status = StatIdle;
if (QueueCounter <= 1)
+ {
+ ErrorText = LookupTag(Message,"Message");
+ Status = StatError;
Owner->Dequeue(this);
+ }
}
/*}}}*/
// Acquire::Item::Done - Item downloaded OK /*{{{*/
--- /dev/null
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+// $Id: acquire-method.cc,v 1.1 1998/10/30 07:53:35 jgg Exp $
+/* ######################################################################
+
+ Acquire Method
+
+ ##################################################################### */
+ /*}}}*/
+// Include Files /*{{{*/
+#ifdef __GNUG__
+#pragma implementation "apt-pkg/acquire-method.h"
+#endif
+#include <apt-pkg/acquire-method.h>
+#include <apt-pkg/error.h>
+#include <apt-pkg/configuration.h>
+#include <strutl.h>
+#include <apt-pkg/fileutl.h>
+
+#include <stdio.h>
+ /*}}}*/
+
+// AcqMethod::pkgAcqMethod - Constructor /*{{{*/
+// ---------------------------------------------------------------------
+/* This constructs the initialization text */
+pkgAcqMethod::pkgAcqMethod(const char *Ver,unsigned long Flags)
+{
+ char S[300] = "";
+ char *End = S;
+ strcat(End,"100 Capabilities\n");
+ sprintf(End+strlen(End),"Version: %s\n",Ver);
+
+ if ((Flags & SingleInstance) == SingleInstance)
+ strcat(End,"Single-Instance: true\n");
+
+ if ((Flags & PreScan) == PreScan)
+ strcat(End,"Pre-Scan: true\n");
+
+ if ((Flags & Pipeline) == Pipeline)
+ strcat(End,"Pipeline: true\n");
+
+ if ((Flags & SendConfig) == SendConfig)
+ strcat(End,"Send-Config: true\n");
+ strcat(End,"\n");
+
+ if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
+ exit(100);
+}
+ /*}}}*/
+// AcqMethod::Fail - A fetch has failed /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void pkgAcqMethod::Fail()
+{
+ string Err = "Undetermined Error";
+ if (_error->empty() == false)
+ _error->PopMessage(Err);
+ _error->Discard();
+ Fail(Err);
+}
+ /*}}}*/
+// AcqMethod::Fail - A fetch has failed /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void pkgAcqMethod::Fail(string Err)
+{
+ char S[1024];
+ snprintf(S,sizeof(S),"400 URI Failure\nURI: %s\n"
+ "Message %s\n\n",CurrentURI.c_str(),Err.c_str());
+
+ if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
+ exit(100);
+}
+ /*}}}*/
+// AcqMethod::URIStart - Indicate a download is starting /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void pkgAcqMethod::URIStart(FetchResult &Res,unsigned long Resume = 0)
+{
+ char S[1024] = "";
+ char *End = S;
+
+ End += snprintf(S,sizeof(S),"200 URI Start\nURI: %s\n",CurrentURI.c_str());
+ if (Res.Size != 0)
+ End += snprintf(End,sizeof(S) - (End - S),"Size: %u\n",Res.Size);
+
+ if (Res.LastModified != 0)
+ End += snprintf(End,sizeof(S) - (End - S),"Last-Modified: %s\n",
+ TimeRFC1123(Res.LastModified).c_str());
+
+ if (Resume != 0)
+ End += snprintf(End,sizeof(S) - (End - S),"Resume-Point: %u\n",
+ Resume);
+
+ strcat(End,"\n");
+ if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
+ exit(100);
+}
+ /*}}}*/
+// AcqMethod::URIDone - A URI is finished /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void pkgAcqMethod::URIDone(FetchResult &Res, FetchResult *Alt)
+{
+ char S[1024] = "";
+ char *End = S;
+
+ End += snprintf(S,sizeof(S),"201 URI Done\nURI: %s\n",CurrentURI.c_str());
+
+ if (Res.Filename.empty() == false)
+ End += snprintf(End,sizeof(S) - (End - S),"Filename: %s\n",Res.Filename.c_str());
+
+ if (Res.Size != 0)
+ End += snprintf(End,sizeof(S) - (End - S),"Size: %u\n",Res.Size);
+
+ if (Res.LastModified != 0)
+ End += snprintf(End,sizeof(S) - (End - S),"Last-Modified: %s\n",
+ TimeRFC1123(Res.LastModified).c_str());
+
+ if (Res.MD5Sum.empty() == false)
+ End += snprintf(End,sizeof(S) - (End - S),"MD5Sum: %s\n",Res.MD5Sum.c_str());
+
+ if (Res.IMSHit == true)
+ strcat(End,"IMS-Hit: true\n");
+ End = S + strlen(S);
+
+ if (Alt != 0)
+ {
+ if (Alt->Filename.empty() == false)
+ End += snprintf(End,sizeof(S) - (End - S),"Alt-Filename: %s\n",Alt->Filename.c_str());
+
+ if (Alt->Size != 0)
+ End += snprintf(End,sizeof(S) - (End - S),"Alt-Size: %u\n",Alt->Size);
+
+ if (Alt->LastModified != 0)
+ End += snprintf(End,sizeof(S) - (End - S),"Alt-Last-Modified: %s\n",
+ TimeRFC1123(Alt->LastModified).c_str());
+
+ if (Alt->MD5Sum.empty() == false)
+ End += snprintf(End,sizeof(S) - (End - S),"Alt-MD5Sum: %s\n",
+ Alt->MD5Sum.c_str());
+
+ if (Alt->IMSHit == true)
+ strcat(End,"Alt-IMS-Hit: true\n");
+ }
+
+ strcat(End,"\n");
+ if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
+ exit(100);
+}
+ /*}}}*/
+// AcqMethod::Configuration - Handle the configuration message /*{{{*/
+// ---------------------------------------------------------------------
+/* This parses each configuration entry and puts it into the _config
+ Configuration class. */
+bool pkgAcqMethod::Configuration(string Message)
+{
+ ::Configuration &Cnf = *_config;
+
+ const char *I = Message.begin();
+
+ unsigned int Length = strlen("Config-Item");
+ for (; I + Length < Message.end(); I++)
+ {
+ // Not a config item
+ if (I[Length] != ':' || stringcasecmp(I,I+Length,"Config-Item") != 0)
+ continue;
+
+ I += Length + 1;
+
+ for (; I < Message.end() && *I == ' '; I++);
+ const char *Equals = I;
+ for (; Equals < Message.end() && *Equals != '='; Equals++);
+ const char *End = Equals;
+ for (; End < Message.end() && *End != '\n'; End++);
+ if (End == Equals)
+ return false;
+
+ Cnf.Set(string(I,Equals-I),string(Equals+1,End-Equals-1));
+ I = End;
+ }
+
+ return true;
+}
+ /*}}}*/
+// AcqMethod::Run - Run the message engine /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+int pkgAcqMethod::Run()
+{
+ SetNonBlock(STDIN_FILENO,true);
+
+ while (1)
+ {
+ if (Messages.empty() == true)
+ if (WaitFd(STDIN_FILENO) == false)
+ return 0;
+
+ if (ReadMessages(STDIN_FILENO,Messages) == false)
+ return 0;
+
+ string Message = Messages.front();
+ Messages.erase(Messages.begin());
+
+ // Fetch the message number
+ char *End;
+ int Number = strtol(Message.c_str(),&End,10);
+ if (End == Message.c_str())
+ {
+ cerr << "Malformed message!" << endl;
+ return 100;
+ }
+
+ switch (Number)
+ {
+ case 601:
+ if (Configuration(Message) == false)
+ return 100;
+ break;
+
+ case 600:
+ {
+ CurrentURI = LookupTag(Message,"URI");
+ DestFile = LookupTag(Message,"FileName");
+ StrToTime(LookupTag(Message,"Last-Modified"),LastModified);
+
+ if (Fetch(Message,CurrentURI) == false)
+ Fail();
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+ /*}}}*/
+// AcqMethod::FetchResult::FetchResult - Constructor /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+pkgAcqMethod::FetchResult::FetchResult() : LastModified(0),
+ IMSHit(false), Size(0)
+{
+}
+ /*}}}*/
+
--- /dev/null
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+// $Id: acquire-method.h,v 1.1 1998/10/30 07:53:35 jgg Exp $
+/* ######################################################################
+
+ Acquire Method - Method helper class + functions
+
+ These functions are designed to be used within the method task to
+ ease communication with APT.
+
+ ##################################################################### */
+ /*}}}*/
+#ifndef PKGLIB_ACQUIRE_METHOD_H
+#define PKGLIB_ACQUIRE_METHOD_H
+
+#include <apt-pkg/configuration.h>
+#include <strutl.h>
+
+#ifdef __GNUG__
+#pragma interface "apt-pkg/acquire-method.h"
+#endif
+
+class pkgAcqMethod
+{
+ protected:
+
+ string CurrentURI;
+ string DestFile;
+ time_t LastModified;
+
+ vector<string> Messages;
+
+ struct FetchResult
+ {
+ string MD5Sum;
+ time_t LastModified;
+ bool IMSHit;
+ string Filename;
+ unsigned long Size;
+ FetchResult();
+ };
+
+ // Handlers for messages
+ virtual bool Configuration(string Message);
+ virtual bool Fetch(string Message,URI Get) {return true;};
+
+ // Outgoing messages
+ void Fail();
+ void Fail(string Why);
+// void Log(const char *Format,...);
+ void URIStart(FetchResult &Res,unsigned long Resume = 0);
+ void URIDone(FetchResult &Res,FetchResult *Alt = 0);
+
+ public:
+
+ enum CnfFlags {SingleInstance = (1<<0), PreScan = (1<<1),
+ Pipeline = (1<<2), SendConfig = (1<<3)};
+
+ int Run();
+
+ pkgAcqMethod(const char *Ver,unsigned long Flags = 0);
+ virtual ~pkgAcqMethod() {};
+};
+
+#endif
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: acquire-worker.cc,v 1.7 1998/10/26 07:11:45 jgg Exp $
+// $Id: acquire-worker.cc,v 1.8 1998/10/30 07:53:35 jgg Exp $
/* ######################################################################
Acquire Worker
{
if (Itm == 0)
{
- _error->Warning("Method gave invalid 200 URI Start message");
+ _error->Error("Method gave invalid 200 URI Start message");
break;
}
CurrentItem = Itm;
{
if (Itm == 0)
{
- _error->Warning("Method gave invalid 400 URI Failure message");
+ _error->Error("Method gave invalid 201 URI Done message");
break;
}
{
if (Itm == 0)
{
- _error->Warning("Method gave invalid 400 URI Failure message");
+ _error->Error("Method gave invalid 400 URI Failure message");
break;
}
return false;
}
/*}}}*/
-
-// InjectConfiguration - Configuration aid for methods /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-bool pkgInjectConfiguration(string &Message,Configuration &Cnf)
-{
- const char *I = Message.begin();
-
- unsigned int Length = strlen("Config-Item");
- for (; I + Length < Message.end(); I++)
- {
- // Not a config item
- if (I[Length] != ':' || stringcasecmp(I,I+Length,"Config-Item") != 0)
- continue;
-
- I += Length + 1;
-
- for (; I < Message.end() && *I == ' '; I++);
- const char *Equals = I;
- for (; Equals < Message.end() && *Equals != '='; Equals++);
- const char *End = Equals;
- for (; End < Message.end() && *End != '\n'; End++);
- if (End == Equals)
- return false;
-
- Cnf.Set(string(I,Equals-I),string(Equals+1,End-Equals-1));
- I = End;
- }
-
- return true;
-}
- /*}}}*/
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: acquire-worker.h,v 1.5 1998/10/26 07:11:46 jgg Exp $
+// $Id: acquire-worker.h,v 1.6 1998/10/30 07:53:36 jgg Exp $
/* ######################################################################
Acquire Worker - Worker process manager
#define PKGLIB_ACQUIRE_WORKER_H
#include <apt-pkg/acquire.h>
-#include <apt-pkg/configuration.h>
#ifdef __GNUG__
#pragma interface "apt-pkg/acquire-worker.h"
~Worker();
};
-bool pkgInjectConfiguration(string &Message,Configuration &Cnf);
-
#endif
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: acquire.cc,v 1.5 1998/10/26 07:11:47 jgg Exp $
+// $Id: acquire.cc,v 1.6 1998/10/30 07:53:37 jgg Exp $
/* ######################################################################
Acquire - File Acquiration
// Acquire::pkgAcquire - Constructor /*{{{*/
// ---------------------------------------------------------------------
-/* */
+/* We grab some runtime state from the configuration space */
pkgAcquire::pkgAcquire()
{
Queues = 0;
/*}}}*/
// Acquire::~pkgAcquire - Destructor /*{{{*/
// ---------------------------------------------------------------------
-/* Free our memory */
+/* Free our memory, clean up the queues (destroy the workers) */
pkgAcquire::~pkgAcquire()
{
while (Items.size() != 0)
/*}}}*/
// Acquire::Add - Add a new item /*{{{*/
// ---------------------------------------------------------------------
-/* */
+/* This puts an item on the acquire list. This list is mainly for tracking
+ item status */
void pkgAcquire::Add(Item *Itm)
{
Items.push_back(Itm);
/*}}}*/
// Acquire::Remove - Remove a item /*{{{*/
// ---------------------------------------------------------------------
-/* */
+/* Remove an item from the acquire list. This is usually not used.. */
void pkgAcquire::Remove(Item *Itm)
{
for (vector<Item *>::iterator I = Items.begin(); I < Items.end(); I++)
/*}}}*/
// Acquire::Add - Add a worker /*{{{*/
// ---------------------------------------------------------------------
-/* */
+/* A list of workers is kept so that the select loop can direct their FD
+ usage. */
void pkgAcquire::Add(Worker *Work)
{
Work->NextAcquire = Workers;
/*}}}*/
// Acquire::Remove - Remove a worker /*{{{*/
// ---------------------------------------------------------------------
-/* */
+/* A worker has died. This can not be done while the select loop is running
+ as it would require that RunFds could handling a changing list state and
+ it cant.. */
void pkgAcquire::Remove(Worker *Work)
{
+ if (Running == true)
+ abort();
+
Worker **I = &Workers;
for (; *I != 0;)
{
/*}}}*/
// Acquire::Enqueue - Queue an URI for fetching /*{{{*/
// ---------------------------------------------------------------------
-/* */
+/* This is the entry point for an item. An item calls this function when
+ it is construction which creates a queue (based on the current queue
+ mode) and puts the item in that queue. If the system is running then
+ the queue might be started. */
void pkgAcquire::Enqueue(Item *Itm,string URI,string Description)
{
// Determine which queue to put the item in
I = new Queue(Name,this);
I->Next = Queues;
Queues = I;
+
+ if (Running == true)
+ I->Startup();
}
// Queue it into the named queue
I->Enqueue(Itm,URI,Description);
ToFetch++;
-
- if (Running == true)
- I->Startup();
-
+
// Some trace stuff
if (Debug == true)
{
/*}}}*/
// Acquire::Dequeue - Remove an item from all queues /*{{{*/
// ---------------------------------------------------------------------
-/* */
+/* This is called when an item is finished being fetched. It removes it
+ from all the queues */
void pkgAcquire::Dequeue(Item *Itm)
{
Queue *I = Queues;
for (; I != 0; I = I->Next)
I->Dequeue(Itm);
+
+ if (Debug == true)
+ clog << "Dequeuing " << Itm->DestFile << endl;
ToFetch--;
}
/*}}}*/
/* The string returned depends on the configuration settings and the
method parameters. Given something like http://foo.org/bar it can
return http://foo.org or http */
-string pkgAcquire::QueueName(string URI)
+string pkgAcquire::QueueName(string Uri)
{
- const MethodConfig *Config = GetConfig(URIAccess(URI));
+ URI U(Uri);
+
+ const MethodConfig *Config = GetConfig(U.Access);
if (Config == 0)
return string();
/* Single-Instance methods get exactly one queue per URI. This is
also used for the Access queue method */
if (Config->SingleInstance == true || QueueMode == QueueAccess)
- return URIAccess(URI);
-
- // Host based queue
- string::iterator I = URI.begin();
- for (; I < URI.end() && *I != ':'; I++);
- for (; I < URI.end() && (*I == '/' || *I == ':'); I++);
- for (; I < URI.end() && *I != '/'; I++);
-
- return string(URI,0,I - URI.begin());
+ return U.Access;
+
+ return U.Access + ':' + U.Host;
}
/*}}}*/
// Acquire::GetConfig - Fetch the configuration information /*{{{*/
/*}}}*/
// Acquire::RunFds - Deal with active FDs /*{{{*/
// ---------------------------------------------------------------------
-/* Dispatch active FDs over to the proper workers */
+/* Dispatch active FDs over to the proper workers. It is very important
+ that a worker never be erased while this is running! The queue class
+ should never erase a worker except during shutdown processing. */
void pkgAcquire::RunFds(fd_set *RSet,fd_set *WSet)
{
for (Worker *I = Workers; I != 0; I = I->NextAcquire)
Running = false;
return _error->Errno("select","Select has failed");
}
-
+
RunFds(&RFds,&WFds);
+ if (_error->PendingError() == true)
+ break;
}
for (Queue *I = Queues; I != 0; I = I->Next)
I->Shutdown();
Running = false;
- return true;
+ return _error->PendingError();
+}
+ /*}}}*/
+// pkgAcquire::Bump - Called when an item is dequeued /*{{{*/
+// ---------------------------------------------------------------------
+/* This routine bumps idle queues in hopes that they will be able to fetch
+ the dequeued item */
+void pkgAcquire::Bump()
+{
+
}
/*}}}*/
Items->URI = URI;
Items->Description = Description;
Owner->QueueCounter++;
+
+ if (Items->Next == 0)
+ Cycle();
}
/*}}}*/
// Queue::Dequeue - Remove an item from the queue /*{{{*/
{
Shutdown();
- pkgAcquire::MethodConfig *Cnf = Owner->GetConfig(URIAccess(Name));
+ URI U(Name);
+ pkgAcquire::MethodConfig *Cnf = Owner->GetConfig(U.Access);
if (Cnf == 0)
return false;
Owner->Add(Workers);
if (Workers->Start() == false)
return false;
-
- Items->Worker = Workers;
- Workers->QueueItem(Items);
- return true;
+ return Cycle();
}
/*}}}*/
// Queue::Shutdown - Shutdown the worker processes /*{{{*/
// Queue::ItemDone - Item has been completed /*{{{*/
// ---------------------------------------------------------------------
/* The worker signals this which causes the item to be removed from the
- queue. */
+ queue. If this is the last queue instance then it is removed from the
+ main queue too.*/
bool pkgAcquire::Queue::ItemDone(QItem *Itm)
{
- Dequeue(Itm->Owner);
+ if (Itm->Owner->QueueCounter <= 1)
+ Owner->Dequeue(Itm->Owner);
+ else
+ {
+ Dequeue(Itm->Owner);
+ Owner->Bump();
+ }
- if (Items == 0)
+ return Cycle();
+}
+ /*}}}*/
+// Queue::Cycle - Queue new items into the method /*{{{*/
+// ---------------------------------------------------------------------
+/* This locates a new idle item and sends it to the worker */
+bool pkgAcquire::Queue::Cycle()
+{
+ if (Items == 0 || Workers == 0)
return true;
- Items->Worker = Workers;
- Items->Owner->Status = pkgAcquire::Item::StatFetching;
- return Workers->QueueItem(Items);
+ // Look for a queable item
+ QItem *I = Items;
+ for (; I != 0; I = I->Next)
+ if (I->Owner->Status == pkgAcquire::Item::StatIdle)
+ break;
+
+ // Nothing to do, queue is idle.
+ if (I == 0)
+ return true;
+
+ I->Worker = Workers;
+ I->Owner->Status = pkgAcquire::Item::StatFetching;
+ return Workers->QueueItem(I);
}
/*}}}*/
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: acquire.h,v 1.5 1998/10/26 07:11:48 jgg Exp $
+// $Id: acquire.h,v 1.6 1998/10/30 07:53:38 jgg Exp $
/* ######################################################################
Acquire - File Acquiration
// FDSET managers for derived classes
void SetFds(int &Fd,fd_set *RSet,fd_set *WSet);
void RunFds(fd_set *RSet,fd_set *WSet);
+
+ // A queue calls this when it dequeues an item
+ void Bump();
public:
bool Startup();
bool Shutdown();
+ bool Cycle();
Queue(string Name,pkgAcquire *Owner);
~Queue();
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: configuration.cc,v 1.8 1998/10/22 04:56:45 jgg Exp $
+// $Id: configuration.cc,v 1.9 1998/10/30 07:53:42 jgg Exp $
/* ######################################################################
Configuration Class
return true;
}
/*}}}*/
+// Configuration::Dump - Dump the config /*{{{*/
+// ---------------------------------------------------------------------
+/* Dump the entire configuration space */
+void Configuration::Dump()
+{
+ /* Write out all of the configuration directives by walking the
+ configuration tree */
+ const Configuration::Item *Top = _config->Tree(0);
+ for (; Top != 0;)
+ {
+ clog << Top->FullTag() << " \"" << Top->Value << "\";" << endl;
+
+ if (Top->Child != 0)
+ {
+ Top = Top->Child;
+ continue;
+ }
+
+ while (Top != 0 && Top->Next == 0)
+ Top = Top->Parent;
+ if (Top != 0)
+ Top = Top->Next;
+ }
+}
+ /*}}}*/
// Configuration::Item::FullTag - Return the fully scoped tag /*{{{*/
// ---------------------------------------------------------------------
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: configuration.h,v 1.6 1998/10/22 04:56:46 jgg Exp $
+// $Id: configuration.h,v 1.7 1998/10/30 07:53:44 jgg Exp $
/* ######################################################################
Configuration Class
bool Exists(const char *Name);
inline const Item *Tree(const char *Name) {return Lookup(Name,false);};
+
+ void Dump();
Configuration();
};
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: strutl.cc,v 1.8 1998/10/24 04:58:07 jgg Exp $
+// $Id: strutl.cc,v 1.9 1998/10/30 07:53:45 jgg Exp $
/* ######################################################################
String Util - Some usefull string functions.
return URI;
}
/*}}}*/
-// URIAccess - Return the access method for the URI /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-string URIAccess(string URI)
-{
- string::size_type Pos = URI.find(':');
- if (Pos == string::npos)
- return URI;
- return string(URI,0,Pos);
-}
- /*}}}*/
// Base64Encode - Base64 Encoding routine for short strings /*{{{*/
// ---------------------------------------------------------------------
/* This routine performs a base64 transformation on a string. It was ripped
return true;
}
/*}}}*/
+
+// URI::URI - Constructor /*{{{*/
+// ---------------------------------------------------------------------
+/* This parses the URI into all of its components */
+URI::URI(string U)
+{
+ string::const_iterator I = U.begin();
+
+ // Locate the first colon, this seperates the scheme
+ for (; I < U.end() && *I != ':' ; I++);
+ string::const_iterator FirstColon = I;
+
+ // Determine if this is a host type URI with a leading double //
+ string::const_iterator SingleSlash = I;
+ if (I + 3 < U.end() && I[1] == '/' && I[2] == '/')
+ {
+ // Locate the single / that starts the path
+ for (; I < U.end(); I++)
+ {
+ if (*I == '/' && I[1] == '/')
+ I += 2;
+ else
+ if (*I == '/')
+ break;
+ }
+ if (I > U.end())
+ I = U.end();
+ SingleSlash = I;
+ }
+
+ // We can now write the access and path specifiers
+ Access = string(U,0,FirstColon - U.begin());
+ if (SingleSlash != U.end())
+ Path = string(U,SingleSlash - U.begin() + 1);
+
+ // Now we attempt to locate a user:pass@host fragment
+ FirstColon += 3;
+ if (FirstColon >= U.end())
+ return;
+
+ if (FirstColon > SingleSlash)
+ FirstColon = SingleSlash;
+
+ // Search for the @
+ I = FirstColon;
+ for (; I < SingleSlash && *I != '@'; I++);
+ string::const_iterator At = I;
+
+ // Colon in the @ section
+ I = FirstColon + 1;
+ for (; I < At && *I != ':'; I++);
+ string::const_iterator SecondColon = I;
+
+ // Now write the host and user/pass
+ if (At == SingleSlash)
+ {
+ if (FirstColon < SingleSlash)
+ Host = string(U,FirstColon - U.begin(),SingleSlash - FirstColon);
+ }
+ else
+ {
+ Host = string(U,At - U.begin() + 1,SingleSlash - At - 1);
+ User = string(U,FirstColon - U.begin(),SecondColon - FirstColon);
+ if (SecondColon < At)
+ Password = string(U,SecondColon - U.begin() + 1,At - SecondColon - 1);
+ }
+
+ // Now we parse off a pot number from the hostname
+ Port = 0;
+ string::size_type Pos = Host.rfind(':');
+ if (Pos == string::npos)
+ return;
+
+ Port = atoi(string(Host,Pos+1).c_str());
+ Host = string(Host,0,Pos);
+}
+ /*}}}*/
+// URI::operator string - Convert the URI to a string /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+URI::operator string()
+{
+ string Res = Access + ':';
+ if (Host.empty() == false)
+ {
+ if (User.empty() == false)
+ {
+ Res += "//" + User;
+ if (Password.empty() == false)
+ Res += ":" + Password;
+ Res += "@";
+ }
+ Res += Host;
+ }
+
+ if (Path.empty() == false)
+ Res += "/" + Path;
+
+ return Res;
+}
+ /*}}}*/
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: strutl.h,v 1.7 1998/10/23 00:50:00 jgg Exp $
+// $Id: strutl.h,v 1.8 1998/10/30 07:53:46 jgg Exp $
/* ######################################################################
String Util - These are some usefull string functions
string SubstVar(string Str,string Subst,string Contents);
string Base64Encode(string Str);
string URItoFileName(string URI);
-string URIAccess(string URI);
string TimeRFC1123(time_t Date);
bool StrToTime(string Val,time_t &Result);
string LookupTag(string Message,const char *Tag,const char *Default = 0);
int stringcasecmp(const char *A,const char *AEnd,const char *B,const char *BEnd);
inline int stringcasecmp(const char *A,const char *AEnd,const char *B) {return stringcasecmp(A,AEnd,B,B+strlen(B));};
+class URI
+{
+ public:
+
+ string Access;
+ string User;
+ string Password;
+ string Host;
+ string Path;
+ unsigned int Port;
+
+ operator string();
+
+ URI(string Path);
+};
+
#endif
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: init.cc,v 1.8 1998/10/20 02:39:19 jgg Exp $
+// $Id: init.cc,v 1.9 1998/10/30 07:53:39 jgg Exp $
/* ######################################################################
Init - Initialize the package library
/*}}}*/
// Include files /*{{{*/
#include <apt-pkg/init.h>
+#include <config.h>
#include <sys/stat.h>
#include <unistd.h>
bool pkgInitialize(Configuration &Cnf)
{
// General APT things
- Cnf.Set("APT::Architecture","i386");
+ Cnf.Set("APT::Architecture",ARCHITECTURE);
// State
Cnf.Set("Dir::State","/var/state/apt/");
Cnf.Set("Dir::Etc","/etc/apt/");
Cnf.Set("Dir::Etc::sourcelist","sources.list");
Cnf.Set("Dir::Etc::main","apt.conf");
-
+ Cnf.Set("Dir::Bin::methods","/usr/lib/apt/metods");
+
// Read the main config file
string FName = Cnf.FindFile("Dir::Etc::main");
struct stat Buf;
if (stat(FName.c_str(),&Buf) != 0)
return true;
- return ReadConfigFile(Cnf,FName);
+
+ // Read an alternate config file
+ const char *Cfg = getenv("APT_CONFIG");
+
+ if (ReadConfigFile(Cnf,FName) != true || ReadConfigFile(Cnf,Cfg) != true)
+ return false;
+
+ if (Cnf.FindB("Debug::pkgInitialize",false) == true)
+ Cnf.Dump();
+
+ return true;
}
/*}}}*/
SOURCE+= pkgcache.cc version.cc fileutl.cc pkgcachegen.cc depcache.cc \
orderlist.cc tagfile.cc sourcelist.cc packagemanager.cc \
pkgrecords.cc algorithms.cc acquire.cc acquire-item.cc \
- acquire-worker.cc init.cc templates.cc
+ acquire-worker.cc acquire-method.cc init.cc templates.cc
# Source code for the debian specific components
SOURCE+= deb/deblistparser.cc deb/debrecords.cc
error.h orderlist.h sourcelist.h configuration.h fileutl.h \
packagemanager.h tagfile.h deblistparser.h init.h pkgcache.h \
version.h progress.h pkgrecords.h debrecords.h cmndline.h \
- acquire.h acquire-worker.h acquire-item.h
+ acquire.h acquire-worker.h acquire-item.h acquire-method.h
HEADERS := $(addprefix apt-pkg/,$(HEADERS))
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: tagfile.cc,v 1.12 1998/10/24 04:58:06 jgg Exp $
+// $Id: tagfile.cc,v 1.13 1998/10/30 07:53:41 jgg Exp $
/* ######################################################################
Fast scanner for RFC-822 type header information
return false;
if (Tag.Scan(Start,End - Start) == false)
- {
- cout << string(Start,End-Start) << endl;
return _error->Error("Unable to parse package file");
- }
}
Start += Tag.size();
iOffset += Tag.size();
else
{
if (Fd.Read(End,Size - (End - Buffer)) == false)
- {
- cout << "boink" << endl;
return false;
- }
Left -= Size - (End - Buffer);
End = Buffer + Size;
# but by explicly setting the BUILD variable. Make is invoked from
# within the source itself which is much more compatible with compilation
# environments.
+ifndef NOISY
.SILENT:
+endif
# Search for the build directory
ifdef BUILD
LIB := $(BIN)
OBJ := $(BUILD)/obj/$(SUBDIR)
DEP := $(OBJ)
-DOC := $(BUILD)/doc
+DOC := $(BUILD)/docs
# Module types
LIBRARY_H = $(BASE)/buildlib/library.mak
SRCDIR=@top_srcdir@
SUBDIRS:=./doc ./bin ./bin/methods ./obj ./include/apt-pkg ./include/deity
-SUBDIRS+=./obj/doc ./obj/apt-pkg ./obj/deity ./obj/gui ./obj/cmdline \
+SUBDIRS+=./obj/docs ./obj/apt-pkg ./obj/deity ./obj/gui ./obj/cmdline \
./obj/test ./obj/methods
BUILD:=$(shell pwd)
export BUILD
dnl need a C++ compiler that is semi-standard conformant, exceptions are
dnl not used but STL is.
+dnl 'make -f Makefile startup' will generate the configure file from
+dnl configure.in correctly and can be run at any time
+
AC_INIT(configure.in)
AC_CONFIG_AUX_DIR(buildlib)
AC_CONFIG_HEADER(include/config.h:buildlib/config.h.in)
-// $Id: apt.conf,v 1.6 1998/10/26 07:11:51 jgg Exp $
+// $Id: apt.conf,v 1.7 1998/10/30 07:53:50 jgg Exp $
/* This file is an index of all APT configuration directives. It should
NOT actually be used as a real config file, though it is a completely
valid file.
+
+ In some instances involing filenames it is possible to set the default
+ directory when the path is evaluated. This means you can use relative
+ paths within the sub scope.
+
+ The configuration directives are specified in a tree with {} designating
+ a subscope relative to the tag before the {}. You can further specify
+ a subscope using scope notation eg,
+ APT::Architecture "i386";
+ This is prefixed with the current scope. Scope notation must be used
+ if an option is specified on the command line with -o.
*/
+// Options for APT in general
APT {
Architecture "i386";
+ // Options for apt-get
Get {
Download-Only "false";
Simulate "false";
Show-Upgraded "false";
};
+ // Some general options
Ingore-Hold "false";
};
+// Options for the downloading routines
Acquire
{
Queue-Mode "access"; // host|access
};
+// Directory layout
Dir
{
-
+ // Location of the state dir
State "/var/state/apt/"
{
lists "lists/";
status "/var/lib/dpkg/status";
};
+ // Location of the cache dir
Cache "/var/cache/apt/" {
archives "archives/";
srcpkgcache "srcpkgcache.bin";
pkgcache "pkgcache.bin";
};
+ // Config files
Etc "/etc/apt/" {
- sourcelist "sources.list.test";
+ sourcelist "sources.list";
main "apt.conf";
};
+ // Locations of binaries
Bin {
methods "/home/jgg/work/apt/build/bin/methods/";
- gzip "gzip";
+ gzip "/bin/gzip";
};
};
}
+/* Options you can set to see some debugging text They corrispond to names
+ of classes in the source code */
Debug {
- pkgProblemResolver "true";
+ pkgProblemResolver "false";
pkgAcquire "false";
- pkgAcquire::Worker "true";
+ pkgAcquire::Worker "false";
+
+ pkgInitialize "false"; // This one will dump the configuration space
}
-
-dir::state::lists "/tmp/lists/";
<title>APT Method Interface </title>
<author>Jason Gunthorpe <email>jgg@debian.org</email></author>
-<version>$Id: method.sgml,v 1.3 1998/10/08 04:55:06 jgg Exp $</version>
+<version>$Id: method.sgml,v 1.4 1998/10/30 07:53:49 jgg Exp $</version>
<abstract>
This document describes the interface that APT uses to the archive
emergency error reporting. The FD's corrispond to the well known unix FD's,
stdin, stdout and stderr.
-<p>
-The basic startup sequence depends on how the method is invoked. If any
-command line arguments are passed then the method should start in
-automatic mode. This facility is provided soley to make the methods
-easier to test and perhaps use outside of APT. Upon startup the method
-will print out a header describing its capabilities and requirements.
-After that it either begins processing the command line arugments and
-exits when done or waits for commands to be fed to it.
-
<p>
Throught operation of the method communication is done via http
style plain text. Specifically RFC-822 (like the Package file) fields
<item>601 Configuration - Sends the configuration space
<item>602 Authorization Credentials - Response to the 402 message
<item>603 Media Changed - Response to the 403 message
-<item>605 Shutdown - Exit
</list>
Only the 6xx series of status codes is sent TO the method. Furthermore
<tag>URI<item>URI being described by the message
<tag>Filename<item>Location in the filesystem
<tag>Last-Modified<item>A time stamp in RFC1123 notation for use by IMS checks
+<tag>IMS-Hit<item>The already existing item is valid
<tag>Size<item>Size of the file in bytes
<tag>Resume-Point<item>Location that transfer was started
<tag>MD5-Hash<item>Computed MD5 hash for the file
This is a yes/no value.
<tag>Pre-Scan<item>Method can detect if archives are already available.
This is a yes/no value.
+<tag>Pipeline<item>The method is capable of pipelining.
+<tag>Send-Config<item>Send configuration to the method.
<tag>Version<item>Version string for the method
</taglist>
<taglist>
<tag>100 Capabilities<item>
-Displays the capabilities of the method.
-Fields: Version, Single-Instance, Pre-Scan
+Displays the capabilities of the method. Methods should set the
+pipeline bit if their underlying protocol supports pipeling. The
+only known method that does support pipelining is http.
+Fields: Version, Single-Instance, Pre-Scan, Pipeline, Send-Config
<tag>101 Log<item>
A log message may be printed to the screen if debugging is enabled. This
mean no data was transfered but the file is now available. A Filename
field is specified when the URI is directly available in the local
pathname space. APT will either directly use that file or copy it into
-another location.
+another location. It is possible to return Alt-* feilds to indicate that
+another possibility for the URI has been found in the local pathname space.
+This is done if a decompressed version of a .gz file is found.
Fields: URI, Size, Last-Modified, Filename, MD5-Hash
<tag>400 URI Failure<item>
This is sent in response to a <em>403 Media Failure</> message. It
indicates that the user has changed media and it is safe to proceed.
Fields: Media
-
-<tag>605 Shutdown<item>
-APT sends this to signal the shutdown of the method. The method should
-terminate immidiately.
-Fields: None
</taglist>
</sect>
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: copy.cc,v 1.3 1998/10/26 07:11:52 jgg Exp $
+// $Id: copy.cc,v 1.4 1998/10/30 07:53:51 jgg Exp $
/* ######################################################################
Copy URI - This method takes a uri like a file: uri and copies it
/*}}}*/
// Include Files /*{{{*/
#include <apt-pkg/fileutl.h>
-#include <strutl.h>
+#include <apt-pkg/acquire-method.h>
#include <apt-pkg/error.h>
#include <sys/stat.h>
#include <utime.h>
#include <unistd.h>
-#include <stdio.h>
/*}}}*/
-// Fail - Generate a failure message /*{{{*/
+class CopyMethod : public pkgAcqMethod
+{
+ virtual bool Fetch(string Message,URI Get);
+
+ public:
+
+ CopyMethod() : pkgAcqMethod("1.0",SingleInstance) {};
+};
+
+// CopyMethod::Fetch - Fetch a file /*{{{*/
// ---------------------------------------------------------------------
/* */
-void Fail(string URI)
+bool CopyMethod::Fetch(string Message,URI Get)
{
- string Err = "Undetermined Error";
- if (_error->empty() == false)
- _error->PopMessage(Err);
+ string File = Get.Path;
+
+ // See if the file exists
+ FileFd From(File,FileFd::ReadOnly);
+ FileFd To(DestFile,FileFd::WriteEmpty);
+ To.EraseOnFailure();
+ if (_error->PendingError() == true)
+ return false;
- printf("400 URI Failure\n"
- "URI: %s\n"
- "Message: %s\n\n",URI.c_str(),Err.c_str());
- _error->Discard();
-}
- /*}}}*/
+ // Copy the file
+ if (CopyFile(From,To) == false)
+ return false;
-int main()
-{
- setlinebuf(stdout);
- SetNonBlock(STDIN_FILENO,true);
+ From.Close();
+ To.Close();
- printf("100 Capabilities\n"
- "Version: 1.0\n"
- "Pipeline: true\n\n");
-
- vector<string> Messages;
- while (1)
+ // Transfer the modification times
+ struct stat Buf;
+ if (stat(File.c_str(),&Buf) != 0)
{
- if (WaitFd(STDIN_FILENO) == false ||
- ReadMessages(STDIN_FILENO,Messages) == false)
- return 0;
-
- while (Messages.empty() == false)
- {
- string Message = Messages.front();
- Messages.erase(Messages.begin());
-
- // Fetch the message number
- char *End;
- int Number = strtol(Message.c_str(),&End,10);
- if (End == Message.c_str())
- {
- cerr << "Malformed message!" << endl;
- return 100;
- }
-
- // We only understand 600 URI Fetch messages
- if (Number != 600)
- continue;
-
- // Grab the URI bit
- string URI = LookupTag(Message,"URI");
- string Target = LookupTag(Message,"Filename");
-
- // Grab the filename
- string::size_type Pos = URI.find(':');
- if (Pos == string::npos)
- {
- _error->Error("Invalid message");
- Fail(URI);
- continue;
- }
- string File = string(URI,Pos+1);
-
- // Start the reply message
- string Result = "201 URI Done";
- Result += "\nURI: " + URI;
- Result += "\nFileName: " + Target;
-
- // See if the file exists
- FileFd From(File,FileFd::ReadOnly);
- FileFd To(Target,FileFd::WriteEmpty);
- To.EraseOnFailure();
- if (_error->PendingError() == true)
- {
- Fail(URI);
- continue;
- }
-
- // Copy the file
- if (CopyFile(From,To) == false)
- {
- Fail(URI);
- continue;
- }
-
- From.Close();
- To.Close();
-
- // Transfer the modification times
- struct stat Buf;
- if (stat(File.c_str(),&Buf) != 0)
- {
- _error->Errno("stat","Failed to stat");
- Fail(URI);
- continue;
- }
- struct utimbuf TimeBuf;
- TimeBuf.actime = Buf.st_atime;
- TimeBuf.modtime = Buf.st_mtime;
- if (utime(Target.c_str(),&TimeBuf) != 0)
- {
- To.OpFail();
- _error->Errno("utime","Failed to set modification time");
- Fail(URI);
- continue;
- }
-
- // Send the message
- Result += "\n\n";
- if (write(STDOUT_FILENO,Result.begin(),Result.length()) !=
- (signed)Result.length())
- return 100;
- }
+ To.OpFail();
+ return _error->Errno("stat","Failed to stat");
}
- return 0;
+ struct utimbuf TimeBuf;
+ TimeBuf.actime = Buf.st_atime;
+ TimeBuf.modtime = Buf.st_mtime;
+ if (utime(DestFile.c_str(),&TimeBuf) != 0)
+ {
+ To.OpFail();
+ return _error->Errno("utime","Failed to set modification time");
+ }
+
+ // Forumulate a result
+ FetchResult Res;
+ Res.Size = Buf.st_size;
+ Res.Filename = DestFile;
+ Res.LastModified = Buf.st_mtime;
+ Res.IMSHit = false;
+
+ URIDone(Res);
+ return true;
+}
+ /*}}}*/
+
+int main()
+{
+ CopyMethod Mth;
+ return Mth.Run();
}
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: file.cc,v 1.3 1998/10/23 00:50:02 jgg Exp $
+// $Id: file.cc,v 1.4 1998/10/30 07:53:52 jgg Exp $
/* ######################################################################
File URI method for APT
##################################################################### */
/*}}}*/
// Include Files /*{{{*/
-#include <apt-pkg/fileutl.h>
-#include <strutl.h>
+#include <apt-pkg/acquire-method.h>
+#include <apt-pkg/error.h>
#include <sys/stat.h>
#include <unistd.h>
-#include <stdio.h>
/*}}}*/
-// Fail - Generate a failure message /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-void Fail(string URI)
+class FileMethod : public pkgAcqMethod
{
- printf("400 URI Failure\n"
- "URI: %s\n"
- "Message: File does not exist\n\n",URI.c_str());
-}
- /*}}}*/
+ virtual bool Fetch(string Message,URI Get);
+
+ public:
+
+ FileMethod() : pkgAcqMethod("1.0",SingleInstance) {};
+};
-int main()
+// FileMethod::Fetch - Fetch a file /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool FileMethod::Fetch(string Message,URI Get)
{
- setlinebuf(stdout);
- SetNonBlock(STDIN_FILENO,true);
+ string File = Get.Path;
+ FetchResult Res;
- printf("100 Capabilities\n"
- "Version: 1.0\n"
- "Pipeline: true\n\n");
-
- vector<string> Messages;
- while (1)
+ // See if the file exists
+ struct stat Buf;
+ if (stat(File.c_str(),&Buf) == 0)
{
- if (WaitFd(STDIN_FILENO) == false ||
- ReadMessages(STDIN_FILENO,Messages) == false)
- return 0;
-
- while (Messages.empty() == false)
+ Res.Size = Buf.st_size;
+ Res.Filename = File;
+ Res.LastModified = Buf.st_mtime;
+ Res.IMSHit = false;
+ if (LastModified == Buf.st_mtime)
+ Res.IMSHit = true;
+ }
+
+ // See if we can compute a file without a .gz exentsion
+ string::size_type Pos = File.rfind(".gz");
+ if (Pos + 3 == File.length())
+ {
+ File = string(File,0,Pos);
+ if (stat(File.c_str(),&Buf) == 0)
{
- string Message = Messages.front();
- Messages.erase(Messages.begin());
-
- // Fetch the message number
- char *End;
- int Number = strtol(Message.c_str(),&End,10);
- if (End == Message.c_str())
- {
- cerr << "Malformed message!" << endl;
- return 100;
- }
+ FetchResult AltRes;
+ AltRes.Size = Buf.st_size;
+ AltRes.Filename = File;
+ AltRes.LastModified = Buf.st_mtime;
+ AltRes.IMSHit = false;
+ if (LastModified == Buf.st_mtime)
+ AltRes.IMSHit = true;
- // We only understand 600 URI Fetch messages
- if (Number != 600)
- continue;
-
- // Grab the URI bit
- string URI = LookupTag(Message,"URI");
-
- // Grab the filename
- string::size_type Pos = URI.find(':');
- if (Pos == string::npos)
- {
- Fail(URI);
- continue;
- }
- string File = string(URI,Pos+1);
-
- // Grab the modification time
- time_t LastMod;
- string LTime = LookupTag(Message,"Last-Modified");
- if (LTime.empty() == false && StrToTime(LTime,LastMod) == false)
- LTime = string();
-
- // Start the reply message
- string Result = "201 URI Done";
- Result += "\nURI: " + URI;
-
- // See if the file exists
- struct stat Buf;
- bool Ok = false;
- if (stat(File.c_str(),&Buf) == 0)
- {
- char S[300];
- sprintf(S,"\nSize: %ld",Buf.st_size);
-
- Result += "\nFilename: " + File;
- Result += S;
- Result += "\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
- if (LTime.empty() == false && LastMod == Buf.st_mtime)
- Result += "\nIMS-Hit: true";
-
- Ok = true;
- }
-
- // See if we can compute a file without a .gz exentsion
- Pos = File.rfind(".gz");
- if (Pos + 3 == File.length())
- {
- File = string(File,0,Pos);
- if (stat(File.c_str(),&Buf) == 0)
- {
- char S[300];
- sprintf(S,"\nAlt-Size: %ld",Buf.st_size);
-
- Result += "\nAlt-Filename: " + File;
- Result += S;
- Result += "\nAlt-Last-Modified: " + TimeRFC1123(Buf.st_mtime);
- if (LTime.empty() == false && LastMod == Buf.st_mtime)
- Result += "\nAlt-IMS-Hit: true";
-
- Ok = true;
- }
- }
-
- // Did we find something?
- if (Ok == false)
- {
- Fail(URI);
- continue;
- }
- Result += "\n\n";
-
- // Send the message
- if (write(STDOUT_FILENO,Result.begin(),Result.length()) !=
- (signed)Result.length())
- return 100;
+ URIDone(Res,&AltRes);
+ return true;
}
}
- return 0;
+ if (Res.Filename.empty() == true)
+ return _error->Error("File not found");
+
+ URIDone(Res);
+ return true;
+}
+ /*}}}*/
+
+int main()
+{
+ FileMethod Mth;
+ return Mth.Run();
}
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: gzip.cc,v 1.2 1998/10/26 07:11:53 jgg Exp $
+// $Id: gzip.cc,v 1.3 1998/10/30 07:53:53 jgg Exp $
/* ######################################################################
GZip method - Take a file URI in and decompress it into the target
// Include Files /*{{{*/
#include <apt-pkg/fileutl.h>
#include <apt-pkg/error.h>
-#include <apt-pkg/configuration.h>
-#include <apt-pkg/acquire-worker.h>
+#include <apt-pkg/acquire-method.h>
#include <strutl.h>
#include <sys/stat.h>
#include <stdio.h>
/*}}}*/
-// Fail - Generate a failure message /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-void Fail(string URI)
+class GzipMethod : public pkgAcqMethod
{
- string Err = "Undetermined Error";
- if (_error->empty() == false)
- _error->PopMessage(Err);
+ virtual bool Fetch(string Message,URI Get);
- printf("400 URI Failure\n"
- "URI: %s\n"
- "Message: %s\n\n",URI.c_str(),Err.c_str());
- _error->Discard();
-}
- /*}}}*/
+ public:
+
+ GzipMethod() : pkgAcqMethod("1.0",SingleInstance | SendConfig) {};
+};
-int main()
+// GzipMethod::Fetch - Decompress the passed URI /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool GzipMethod::Fetch(string Message,URI Get)
{
- setlinebuf(stdout);
- SetNonBlock(STDIN_FILENO,true);
+ // Open the source and destintation files
+ FileFd From(Get.Path,FileFd::ReadOnly);
+ FileFd To(DestFile,FileFd::WriteEmpty);
+ To.EraseOnFailure();
+ if (_error->PendingError() == true)
+ return false;
- printf("100 Capabilities\n"
- "Version: 1.0\n"
- "Pipeline: true\n"
- "Send-Config: true\n\n");
-
- vector<string> Messages;
- while (1)
+ // Fork gzip
+ int Process = fork();
+ if (Process < 0)
+ return _error->Errno("fork","Couldn't fork gzip");
+
+ // The child
+ if (Process == 0)
{
- if (WaitFd(STDIN_FILENO) == false ||
- ReadMessages(STDIN_FILENO,Messages) == false)
- return 0;
-
- while (Messages.empty() == false)
- {
- string Message = Messages.front();
- Messages.erase(Messages.begin());
-
- // Fetch the message number
- char *End;
- int Number = strtol(Message.c_str(),&End,10);
- if (End == Message.c_str())
- {
- cerr << "Malformed message!" << endl;
- return 100;
- }
-
- // 601 configuration message
- if (Number == 601)
- {
- pkgInjectConfiguration(Message,*_config);
- continue;
- }
+ dup2(From.Fd(),STDIN_FILENO);
+ dup2(To.Fd(),STDOUT_FILENO);
+ From.Close();
+ To.Close();
+ SetCloseExec(STDIN_FILENO,false);
+ SetCloseExec(STDOUT_FILENO,false);
+
+ const char *Args[3];
+ Args[0] = _config->Find("Dir::bin::gzip","gzip").c_str();
+ Args[1] = "-d";
+ Args[2] = 0;
+ execvp(Args[0],(char **)Args);
+ exit(100);
+ }
+ From.Close();
+
+ // Wait for gzip to finish
+ int Status;
+ if (waitpid(Process,&Status,0) != Process)
+ {
+ To.OpFail();
+ return _error->Errno("wait","Waiting for gzip failed");
+ }
+
+ if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
+ {
+ To.OpFail();
+ return _error->Error("gzip failed, perhaps the disk is full or the directory permissions are wrong.");
+ }
+
+ To.Close();
+
+ // Transfer the modification times
+ struct stat Buf;
+ if (stat(Get.Path.c_str(),&Buf) != 0)
+ return _error->Errno("stat","Failed to stat");
- // 600 URI Fetch message
- if (Number != 600)
- continue;
-
- // Grab the URI bit
- string URI = LookupTag(Message,"URI");
- string Target = LookupTag(Message,"Filename");
-
- // Grab the filename
- string::size_type Pos = URI.find(':');
- if (Pos == string::npos)
- {
- _error->Error("Invalid message");
- Fail(URI);
- continue;
- }
- string File = string(URI,Pos+1);
-
- // Start the reply message
- string Result = "201 URI Done";
- Result += "\nURI: " + URI;
- Result += "\nFileName: " + Target;
-
- // See if the file exists
- FileFd From(File,FileFd::ReadOnly);
- FileFd To(Target,FileFd::WriteEmpty);
- To.EraseOnFailure();
- if (_error->PendingError() == true)
- {
- Fail(URI);
- continue;
- }
-
- // Fork gzip
- int Process = fork();
- if (Process < 0)
- {
- _error->Errno("fork","Couldn't fork gzip");
- Fail(URI);
- continue;
- }
-
- // The child
- if (Process == 0)
- {
- dup2(From.Fd(),STDIN_FILENO);
- dup2(To.Fd(),STDOUT_FILENO);
- From.Close();
- To.Close();
- SetCloseExec(STDIN_FILENO,false);
- SetCloseExec(STDOUT_FILENO,false);
-
- const char *Args[3];
- Args[0] = _config->Find("Dir::bin::gzip","gzip").c_str();
- Args[1] = "-d";
- Args[2] = 0;
- execvp(Args[0],(char **)Args);
- exit(100);
- }
- From.Close();
-
- // Wait for gzip to finish
- int Status;
- if (waitpid(Process,&Status,0) != Process)
- {
- To.OpFail();
- _error->Errno("wait","Waiting for gzip failed");
- Fail(URI);
- continue;
- }
+ struct utimbuf TimeBuf;
+ TimeBuf.actime = Buf.st_atime;
+ TimeBuf.modtime = Buf.st_mtime;
+ if (utime(DestFile.c_str(),&TimeBuf) != 0)
+ return _error->Errno("utime","Failed to set modification time");
- if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
- {
- To.OpFail();
- _error->Error("gzip failed, perhaps the disk is full or the directory permissions are wrong.");
- Fail(URI);
- continue;
- }
-
- To.Close();
-
- // Transfer the modification times
- struct stat Buf;
- if (stat(File.c_str(),&Buf) != 0)
- {
- _error->Errno("stat","Failed to stat");
- Fail(URI);
- continue;
- }
- struct utimbuf TimeBuf;
- TimeBuf.actime = Buf.st_atime;
- TimeBuf.modtime = Buf.st_mtime;
- if (utime(Target.c_str(),&TimeBuf) != 0)
- {
- _error->Errno("utime","Failed to set modification time");
- Fail(URI);
- continue;
- }
-
- // Send the message
- Result += "\n\n";
- if (write(STDOUT_FILENO,Result.begin(),Result.length()) !=
- (signed)Result.length())
- return 100;
- }
- }
+ // Return a Done response
+ FetchResult Res;
+ Res.LastModified = Buf.st_mtime;
+ Res.Filename = DestFile;
+ URIDone(Res);
- return 0;
+ return true;
+}
+ /*}}}*/
+
+int main()
+{
+ GzipMethod Mth;
+ return Mth.Run();
}
#include <apt-pkg/init.h>
#include <apt-pkg/error.h>
#include <signal.h>
+#include <strutl.h>
-int main()
+int main(int argc,char *argv[])
{
signal(SIGPIPE,SIG_IGN);
+
+/* URI Foo(argv[1]);
+ cout << Foo.Access << '\'' << endl;
+ cout << Foo.Host << '\'' << endl;
+ cout << Foo.Path << '\'' << endl;
+ cout << Foo.User << '\'' << endl;
+ cout << Foo.Password << '\'' << endl;
+ cout << Foo.Port << endl;
+
+ return 0;*/
pkgInitialize(*_config);