Second part of my work in SoC was implement support of DEB-based distribution in OVAL interpreter. After discussion with my mentor i choice libapt for interacting with Debian package system.
But i have a troubles with this library because it have poor documentation. I start use regression test, which i found in library source but some of them seems broken. After some attempt to find problem i move to apt-get source and use them to build my first package querying program. apt-get use dpkg cache file to obtain information about all available packages. Therefor source for querying packages from dpkg cache file seems like:
bool checkExist (string package)
{
bool exist = false;
pkgCacheFile *Cache = new pkgCacheFile();
OpTextProgress Prog(*_config);
if (Cache->Open(Prog, true) == false) {
cerr << "I need more priveleges." << endl;
}
pkgCache::PkgIterator Pkg = (*Cache)->FindPkg (package);
if (strcmp (Pkg.Name(), package.c_str()) == 0 and (Pkg.CurrentVer()))
exist = true;
Cache->Close();
return (exist);
}
I think this approach is good and compact but have one lack in size of querying cache. Because we query over all available packages, not only installed. And for my machine this number about 20000.
My mentor Javier propose another approach based on apt-sort source code. This approach use dpkg status file for querying information about installed packages. There another version of checkExist function:
bool DPKGCheckExist (string name)
{
FileFd Fd(StatusFile, StatusFile::ReadOnly);
pkgTagFile Tags(&Fd);
bool found = false;
if (_error->PendingError() == true)
return "false";
// Parse.
vector List;
pkgTagSection Section;
unsigned long Offset = Tags.Offset();
while (Tags.Step(Section) == true && found == false)
{
PkgName Tmp;
/* Fetch the name, auto-detecting if this is a source file or a package file */
Tmp.Name = Section.FindS("Package");
if (Tmp.Name.empty() == true)
//return _error->Error("Unknown package record!");
return "false";
if ( stringcasecmp(Tmp.Name,name) == 0 )
{
if (stringcasecmp(Tmp.Stat,"install ok installed") == 0 )
{
return true;
} else {
cout << "Package not fully installed" << endl;
return false;
}
found = true;
}
Tmp.Offset = Offset;
Tmp.Length = Section.size();
Offset = Tags.Offset();
}
if (found == false)
return "ERROR";
if (_error->PendingError() == true)
return "ERROR";
}
This example contain more code, but also allow to extract more information about installed packages. And this fragments would move to other functions which used to extraction DPKG package information. Currently i use this example in my work.
If you would plan use of libapt in you project this two approach may help you get started in rigth way.