diff options
-rw-r--r-- | cmdline/apt-extracttemplates.cc | 142 | ||||
-rw-r--r-- | cmdline/debfile.cc | 304 | ||||
-rw-r--r-- | cmdline/debfile.h | 45 | ||||
-rw-r--r-- | cmdline/makefile | 7 |
4 files changed, 498 insertions, 0 deletions
diff --git a/cmdline/apt-extracttemplates.cc b/cmdline/apt-extracttemplates.cc new file mode 100644 index 000000000..b7af03005 --- /dev/null +++ b/cmdline/apt-extracttemplates.cc @@ -0,0 +1,142 @@ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#define _GNU_SOURCE +#include <getopt.h> +#include <wait.h> +#include <fstream.h> + +#include <apt-pkg/init.h> +#if APT_PKG_MAJOR >= 3 +#define APT_COMPATIBILITY 986 +#include <apt-pkg/debversion.h> +#endif +#include <apt-pkg/pkgcache.h> +#include <apt-pkg/configuration.h> +#include <apt-pkg/progress.h> +#include <apt-pkg/sourcelist.h> +#include <apt-pkg/pkgcachegen.h> +#include <apt-pkg/version.h> +#include "debfile.h" + +#define TMPDIR "/var/lib/debconf/" +#define STR(x) (x ? x : "") +//#define TMPDIR "tmp/" + +void help(void) +{ + fprintf(stderr, "apt-extracttemplates deb [deb]\n"); + exit(0); +} + +char *writefile(const char *prefix, const char *data) +{ + char fn[512]; + static int i; + snprintf(fn, sizeof(fn), "%s%s.%u%d", TMPDIR, prefix, getpid(), i++); + + if (data == NULL) data = ""; + + ofstream ofs(fn); + if (!ofs) return NULL; + ofs << data; + ofs.close(); + return strdup(fn); +} + +void writeconfig(const DebFile &file) +{ + char *templatefile = writefile("template", file.Template); + char *configscript = writefile("config", file.Config); + + if (templatefile == 0 || configscript == 0) + { + fprintf(stderr, "Cannot write config script or templates\n"); + return; + } + printf("%s %s %s %s\n", + STR(file.Package), // Package + STR(file.Version), // Version + templatefile, // Template + configscript // Config + ); +} + +void init(MMap *&Map, pkgCache *&Cache) +{ + // Initialize the apt cache + if (pkgInitConfig(*_config) == false || pkgInitSystem(*_config, _system) == false) + { + fprintf(stderr, "Cannot initialize apt cache\n"); + return; + } + pkgSourceList List; + List.ReadMainList(); + OpProgress Prog; + pkgMakeStatusCache(List,Prog,&Map,true); + Cache = new pkgCache(Map); +} + +int main(int argc, char **argv, char **env) +{ + int idx = 0; + char **debs = 0; + int numdebs = 0; + MMap *Map = 0; + const char *debconfver = NULL; + + init(Map, DebFile::Cache); + if (Map == 0 || DebFile::Cache == 0) + { + fprintf(stderr, "Cannot initialize APT cache\n"); + return 1; + } + + debconfver = DebFile::GetInstalledVer("debconf"); + + if (debconfver == NULL) + { + fprintf(stderr, "Cannot get debconf version. Is debconf installed?\n"); + return 1; + } + + numdebs = argc - 1; + debs = new char *[numdebs]; + memcpy(debs, &argv[1], sizeof(char *) * numdebs); + + if (numdebs < 1) + { + fprintf(stderr, "apt-extracttemplates foo.deb [...]\n"); + return 0; + } + + for (idx = 0; idx < numdebs; idx++) + { + DebFile file(debs[idx]); + if (file.Go() == false) + { + fprintf(stderr, "Cannot read %s\n", debs[idx]); + continue; + } + if (file.Template != 0 && file.ParseInfo() == true) + { + if (file.DepVer != 0 && *file.DepVer != 0 && + pkgCheckDep(file.DepVer, + debconfver, file.DepOp) == false) + continue; + if (file.PreDepVer != 0 && *file.PreDepVer != 0 && + pkgCheckDep(file.PreDepVer, + debconfver, file.PreDepOp) == false) + continue; + + writeconfig(file); + } + } + + + delete Map; + delete DebFile::Cache; + + return 0; +} diff --git a/cmdline/debfile.cc b/cmdline/debfile.cc new file mode 100644 index 000000000..0aa246226 --- /dev/null +++ b/cmdline/debfile.cc @@ -0,0 +1,304 @@ +#include <stdio.h> +#include <apt-pkg/tagfile.h> +#include <apt-pkg/extracttar.h> +#include <apt-pkg/arfile.h> +#include <apt-pkg/pkgcache.h> + +#include "debfile.h" + +pkgCache *DebFile::Cache = 0; + +DebFile::DebFile(const char *debfile) + : File(debfile, FileFd::ReadOnly), Control(0), Package(0), Version(0), DepVer(0), PreDepVer(0), DepOp(0), PreDepOp(0), Config(0), Template(0), Which(None) +{ +} + +DebFile::~DebFile() +{ + delete [] Control; + delete [] Config; + delete [] Template; +} + +char *DebFile::GetInstalledVer(const char *package) +{ + char *ver = 0; + + pkgCache::PkgIterator Pkg = Cache->FindPkg(package); + if (Pkg.end() == false) + { + pkgCache::VerIterator V = Pkg.CurrentVer(); + if (V.end() == false) + { + ver = strdup(V.VerStr()); + } + } + + return ver; +} + +bool DebFile::Go() +{ + ARArchive AR(File); + const ARArchive::Member *Member = AR.FindMember("control.tar.gz"); + if (Member == 0) + { + fprintf(stderr, "This is not a valid DEB archive.\n"); + return false; + } + + if (File.Seek(Member->Start) == false) + { + return false; + } + + ExtractTar Tar(File, Member->Size); + return Tar.Go(*this); +} + +bool DebFile::DoItem(Item &I, int &Fd) +{ + if (strcmp(I.Name, "control") == 0) + { + delete [] Control; + Control = new char[I.Size+1]; + Control[I.Size] = 0; + Which = IsControl; + ControlLen = I.Size; + // make it call the Process method below. this is so evil + Fd = -2; + } + else if (strcmp(I.Name, "config") == 0) + { + delete [] Config; + Config = new char[I.Size+1]; + Config[I.Size] = 0; + Which = IsConfig; + Fd = -2; + } + else if (strcmp(I.Name, "templates") == 0) + { + delete [] Template; + Template = new char[I.Size+1]; + Template[I.Size] = 0; + Which = IsTemplate; + Fd = -2; + } + else + { + Fd = -1; + } + return true; +} + +bool DebFile::Process(Item &I, const unsigned char *data, + unsigned long size, unsigned long pos) +{ + switch (Which) + { + case IsControl: + memcpy(Control + pos, data, size); + break; + case IsConfig: + memcpy(Config + pos, data, size); + break; + case IsTemplate: + memcpy(Template + pos, data, size); + break; + default: /* throw it away */ ; + } + return true; +} + +bool DebFile::ParseInfo() +{ + if (Control == NULL) return false; + pkgTagSection Section; + Section.Scan(Control, ControlLen); + + const char *pkgtmp = Section.FindS("Package").c_str(); + Package = CopyString(pkgtmp, strlen(pkgtmp)); + Version = GetInstalledVer(Package); + + const char *Start, *Stop; + if (Section.Find("Depends", Start, Stop) == true) + { + while (1) + { + char *P = 0, *V = 0; + unsigned int Op; + Start = ParseDepends(Start, Stop, P, V, Op); + if (Start == 0) return false; + if (strcmp(P, "debconf") == 0) + { + DepVer = V; + DepOp = Op; + delete[] P; + break; + } + else + { + delete[] P; + delete[] V; + } + if (Start == Stop) break; + } + } + + if (Section.Find("Pre-Depends", Start, Stop) == true) + { + while (1) + { + char *P = 0, *V = 0; + unsigned int Op; + Start = ParseDepends(Start, Stop, P, V, Op); + if (Start == 0) return false; + if (strcmp(P, "debconf") == 0) + { + PreDepVer = V; + PreDepOp = Op; + delete[] P; + break; + } + else + { + delete[] P; + delete[] V; + } + if (Start == Stop) break; + } + } + + return true; +} + +char *DebFile::CopyString(const char *start, unsigned int len) +{ + char *s = new char[len + 1]; + s[len] = 0; + memcpy(s, start, len); + return s; +} + +const char *DebFile::ParseDepends(const char *Start,const char *Stop, + char *&Package, char *&Ver, + unsigned int &Op) +{ + // Strip off leading space + for (;Start != Stop && isspace(*Start) != 0; Start++); + + // Parse off the package name + const char *I = Start; + for (;I != Stop && isspace(*I) == 0 && *I != '(' && *I != ')' && + *I != ',' && *I != '|'; I++); + + // Malformed, no '(' + if (I != Stop && *I == ')') + return 0; + + if (I == Start) + return 0; + + // Stash the package name + Package = CopyString(Start, I - Start); + + // Skip white space to the '(' + for (;I != Stop && isspace(*I) != 0 ; I++); + + // Parse a version + if (I != Stop && *I == '(') + { + // Skip the '(' + for (I++; I != Stop && isspace(*I) != 0 ; I++); + if (I + 3 >= Stop) + return 0; + + // Determine the operator + switch (*I) + { + case '<': + I++; + if (*I == '=') + { + I++; + Op = pkgCache::Dep::LessEq; + break; + } + + if (*I == '<') + { + I++; + Op = pkgCache::Dep::Less; + break; + } + + // < is the same as <= and << is really Cs < for some reason + Op = pkgCache::Dep::LessEq; + break; + + case '>': + I++; + if (*I == '=') + { + I++; + Op = pkgCache::Dep::GreaterEq; + break; + } + + if (*I == '>') + { + I++; + Op = pkgCache::Dep::Greater; + break; + } + + // > is the same as >= and >> is really Cs > for some reason + Op = pkgCache::Dep::GreaterEq; + break; + + case '=': + Op = pkgCache::Dep::Equals; + I++; + break; + + // HACK around bad package definitions + default: + Op = pkgCache::Dep::Equals; + break; + } + + // Skip whitespace + for (;I != Stop && isspace(*I) != 0; I++); + Start = I; + for (;I != Stop && *I != ')'; I++); + if (I == Stop || Start == I) + return 0; + + // Skip trailing whitespace + const char *End = I; + for (; End > Start && isspace(End[-1]); End--); + + Ver = CopyString(Start, End - Start); + I++; + } + else + { + Ver = CopyString("", 0); + Op = pkgCache::Dep::NoOp; + } + + // Skip whitespace + for (;I != Stop && isspace(*I) != 0; I++); + + if (I != Stop && *I == '|') + Op |= pkgCache::Dep::Or; + + if (I == Stop || *I == ',' || *I == '|') + { + if (I != Stop) + for (I++; I != Stop && isspace(*I) != 0; I++); + return I; + } + + return 0; +} diff --git a/cmdline/debfile.h b/cmdline/debfile.h new file mode 100644 index 000000000..b2db3c80b --- /dev/null +++ b/cmdline/debfile.h @@ -0,0 +1,45 @@ +#ifndef _debfile_H +#define _debfile_H + +#include <apt-pkg/fileutl.h> +#include <apt-pkg/pkgcache.h> +#include <apt-pkg/dirstream.h> + +class DebFile : public pkgDirStream +{ + const char *ParseDepends(const char *Start,const char *Stop, + char *&Package, char *&Ver, + unsigned int &Op); + + char *CopyString(const char *start, unsigned int len); + + FileFd File; + unsigned long Size; + char *Control; + unsigned long ControlLen; + +public: + DebFile(const char *FileName); + ~DebFile(); + bool DoItem(Item &I, int &fd); + bool Process(pkgDirStream::Item &I, const unsigned char *data, + unsigned long size, unsigned long pos); + + bool Go(); + bool ParseInfo(); + + static char *GetInstalledVer(const char *package); + + char *Package; + char *Version; + char *DepVer, *PreDepVer; + unsigned int DepOp, PreDepOp; + + char *Config; + char *Template; + + static pkgCache *Cache; + enum { None, IsControl, IsConfig, IsTemplate } Which; +}; + +#endif diff --git a/cmdline/makefile b/cmdline/makefile index c0647cead..0f19d8e59 100644 --- a/cmdline/makefile +++ b/cmdline/makefile @@ -39,3 +39,10 @@ SLIBS = -lapt-pkg LIB_MAKES = apt-pkg/makefile SOURCE = apt-sortpkgs.cc include $(PROGRAM_H) + +# The apt-extracttemplates program +PROGRAM=apt-extracttemplates +SLIBS = -lapt-pkg -lapt-inst +LIB_MAKES = apt-pkg/makefile +SOURCE = apt-extracttemplates.cc debfile.cc +include $(PROGRAM_H) |