1904 lines
71 KiB
C
1904 lines
71 KiB
C
/*
|
|
* distromatic - tool for RPM based repositories
|
|
*
|
|
* Copyright (C) 2004-2021 by Silvan Calarco <silvan.calarco@mambasoft.it>
|
|
* Copyright (C) 2006 by Davide Madrisan <davide.madrisan@gmail.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it under
|
|
* the terms of version 2 of the GNU General Public License as published by the
|
|
* Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY, to the extent permitted by law; without even the implied
|
|
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
* See the GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with
|
|
* this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <dirent.h>
|
|
|
|
#include <librepo/librepo.h>
|
|
#include <zlib.h>
|
|
#include <libxml/parser.h>
|
|
|
|
#ifndef H_RPMLIB
|
|
# include <rpm/rpmlib.h>
|
|
#endif
|
|
|
|
#if RPM_VERSION >= 0x040100
|
|
#include <rpm/rpmts.h>
|
|
#else
|
|
#define rpmReadPackageFile(a,b,c,d) rpmReadPackageHeader(b,d,0,NULL,NULL)
|
|
#endif
|
|
|
|
#if HAVE_STRING_H
|
|
# if !STDC_HEADERS && HAVE_MEMORY_H
|
|
# include <memory.h>
|
|
# endif
|
|
# include <string.h>
|
|
#endif
|
|
#if HAVE_STRINGS_H
|
|
# include <strings.h>
|
|
#endif
|
|
|
|
#if STDC_HEADERS
|
|
# include <stdlib.h>
|
|
# include <stddef.h>
|
|
#else
|
|
# if HAVE_STDLIB_H
|
|
# include <stdlib.h>
|
|
# endif
|
|
#endif
|
|
|
|
#include "distromatic.h"
|
|
#include "config.h"
|
|
#include "changelog.h"
|
|
#include "functions.h"
|
|
#include "headerlist.h"
|
|
#include "rpmfunctions.h"
|
|
#include <errno.h>
|
|
|
|
#if !HAVE_MEMCPY
|
|
# define memcpy(d, s, n) bcopy ((s), (d), (n))
|
|
#endif
|
|
|
|
int rpmselector(const struct dirent *entry);
|
|
int sourcerpmselector(const struct dirent *entry);
|
|
|
|
const int bufsize = PATH_MAX;
|
|
|
|
struct warningList* addWarning(struct headerSourceList *pkg, char* text)
|
|
{
|
|
struct warningList *currwarning, *prevwarning = NULL;
|
|
|
|
if (!pkg) return NULL;
|
|
|
|
currwarning = pkg->firstwarning;
|
|
|
|
while (currwarning) {
|
|
if (!strcmp(currwarning->text,text)) return currwarning;
|
|
prevwarning = currwarning;
|
|
currwarning = currwarning->next;
|
|
}
|
|
|
|
currwarning=malloc(sizeof(currwarning));
|
|
if (!currwarning) return NULL;
|
|
if (!pkg->firstwarning) pkg->firstwarning=currwarning;
|
|
|
|
currwarning->text=strdup(text);
|
|
if (!currwarning->text) return NULL;
|
|
|
|
currwarning->next=NULL;
|
|
if (prevwarning) prevwarning->next=currwarning;
|
|
return pkg->firstwarning;
|
|
}
|
|
|
|
struct rebuildList* addRebuild(struct headerSourceList *pkg, struct headerSourceList* sourceheader, struct headerList* provider)
|
|
{
|
|
struct rebuildList *currrebuild, *prevrebuild = NULL;
|
|
|
|
if (!pkg) return NULL;
|
|
|
|
currrebuild = pkg->firstrebuild;
|
|
|
|
while (currrebuild) {
|
|
if ((currrebuild->sourceheader == sourceheader) && (currrebuild->provider == provider)) return currrebuild;
|
|
prevrebuild = currrebuild;
|
|
currrebuild = currrebuild->next;
|
|
}
|
|
|
|
currrebuild=malloc(sizeof(struct rebuildList));
|
|
if (!currrebuild) return NULL;
|
|
if (!pkg->firstrebuild) pkg->firstrebuild=currrebuild;
|
|
|
|
currrebuild->sourceheader=sourceheader;
|
|
currrebuild->provider=provider;
|
|
currrebuild->next=NULL;
|
|
|
|
if (prevrebuild) prevrebuild->next=currrebuild;
|
|
return pkg->firstrebuild;
|
|
}
|
|
|
|
struct headerList *
|
|
findPackageByName(struct headerList *list, char *name)
|
|
{
|
|
struct headerList *currheaderlist;
|
|
|
|
currheaderlist = list;
|
|
|
|
while (currheaderlist) {
|
|
if (strcmp(name, currheaderlist->name) == 0) {
|
|
return currheaderlist;
|
|
}
|
|
currheaderlist = currheaderlist->next;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int getPackageNameFromFile(char *name)
|
|
{
|
|
int idx = rpmnameidx(name);
|
|
if (idx < 0 || idx+1 >= strlen(name)) return 1;
|
|
name[idx + 1] = '\0';
|
|
return 0;
|
|
}
|
|
|
|
struct headerSourceList *
|
|
findSourcePackage(struct headerSourceList *list, char *name, char *version,
|
|
char *release, int altrepository)
|
|
{
|
|
struct headerSourceList *currheaderlist = list;
|
|
struct headerSourceList *oldheaderlist;
|
|
|
|
while (currheaderlist) {
|
|
if (!strcmp(name, currheaderlist->name)) {
|
|
if (((!release) || !strcmp(release, currheaderlist->release)) &&
|
|
((!version) || !strcmp(version, currheaderlist->version)) &&
|
|
((altrepository < 0) || (altrepository == currheaderlist->altrepository)))
|
|
return currheaderlist;
|
|
oldheaderlist = currheaderlist->old;
|
|
while (oldheaderlist) {
|
|
if (((!release) || !strcmp(release, oldheaderlist->release)) &&
|
|
((!version) || !strcmp(version, oldheaderlist->version)) &&
|
|
((altrepository < 0) || (altrepository == oldheaderlist->altrepository)))
|
|
return oldheaderlist;
|
|
oldheaderlist = oldheaderlist->old;
|
|
}
|
|
}
|
|
currheaderlist = currheaderlist->next;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int
|
|
getPackageInfoIntoHeaderList(Header h, struct headerList *hl)
|
|
{
|
|
hl->name = headerGetStringEntry(h, RPMTAG_NAME);
|
|
hl->epoch = headerGetUIntEntry(h, RPMTAG_EPOCH);
|
|
if (hl->epoch == -1) hl->epoch = 0;
|
|
hl->version = headerGetStringEntry(h, RPMTAG_VERSION);
|
|
hl->release = headerGetStringEntry(h, RPMTAG_RELEASE);
|
|
hl->summary = headerGetStringEntry(h, RPMTAG_SUMMARY);
|
|
hl->arch = headerGetStringEntry(h, RPMTAG_ARCH);
|
|
hl->description = headerGetStringEntry(h, RPMTAG_DESCRIPTION);
|
|
hl->sourcename = headerGetStringEntry(h, RPMTAG_SOURCERPM);
|
|
hl->group = headerGetStringEntry(h, RPMTAG_GROUP);
|
|
hl->size = headerGetUIntEntry(h, RPMTAG_SIZE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
getPackageInfoIntoHeaderSourceList(Header h, struct headerSourceList *hl)
|
|
{
|
|
char* packager;
|
|
int count;
|
|
|
|
hl->name = headerGetStringEntry(h, RPMTAG_NAME);
|
|
hl->epoch = headerGetUIntEntry(h, RPMTAG_EPOCH);
|
|
if (hl->epoch == -1) hl->epoch = 0;
|
|
hl->version = headerGetStringEntry(h, RPMTAG_VERSION);
|
|
hl->release = headerGetStringEntry(h, RPMTAG_RELEASE);
|
|
hl->summary = headerGetStringEntry(h, RPMTAG_SUMMARY);
|
|
hl->arch = headerGetStringEntry(h, RPMTAG_ARCH);
|
|
hl->buildarchs = headerGetStringEntry(h, RPMTAG_BUILDARCHS);
|
|
hl->excludearch = headerGetStringEntry(h, RPMTAG_EXCLUDEARCH);
|
|
hl->description = headerGetStringEntry(h, RPMTAG_DESCRIPTION);
|
|
packager = headerGetStringEntry(h, RPMTAG_PACKAGER);
|
|
if (!packager) {
|
|
logmsg(LOG_WARNING,"missing packager definition in package %s.",hl->name);
|
|
hl->packager = NULL;
|
|
} else {
|
|
hl->packager = getPackagerByName(packager,1);
|
|
if (!hl->packager) {
|
|
logmsg(LOG_WARNING,"cannot create '%s' packager for package %s.",packager,hl->name);
|
|
free(packager);
|
|
}
|
|
/* if (! (hl->packager->role && PACKAGER_ROLE_MAINTAINER)) {
|
|
logmsg(LOG_WARNING,"%s is an unmaintained package.",hl->name,hl->packager->name,hl->packager->role);
|
|
}*/
|
|
}
|
|
hl->group = headerGetStringEntry(h, RPMTAG_GROUP);
|
|
hl->license = headerGetStringEntry(h, RPMTAG_LICENSE);
|
|
hl->url = headerGetStringEntry(h, RPMTAG_URL);
|
|
if (!hl->url)
|
|
logmsg(LOG_WARNING,"missing URL definition for package %s.",hl->name);
|
|
hl->buildtime = headerGetUIntEntry(h, RPMTAG_BUILDTIME);
|
|
|
|
hl->source = headerGetStringArrayEntry(h, RPMTAG_SOURCE, &count);
|
|
hl->patch = headerGetStringArrayEntry(h, RPMTAG_PATCH, &count);
|
|
hl->size = headerGetUIntEntry(h, RPMTAG_SIZE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
compareSourceHeaderBuildDate(const void *ptr1, const void *ptr2)
|
|
{
|
|
return (int) ((*(struct headerSourceList **)ptr2)->buildtime -
|
|
(*(struct headerSourceList **)ptr1)->buildtime);
|
|
}
|
|
|
|
int
|
|
compareGroup(const void *ptr1, const void *ptr2)
|
|
{
|
|
return (int) strcmp((*(struct headerSourceList **)ptr1)->group,
|
|
(*(struct headerSourceList **)ptr2)->group);
|
|
}
|
|
|
|
int
|
|
generateHeaderStats(struct configTag *ct, int arch)
|
|
{
|
|
int c;
|
|
struct headerList *currheaderlist;
|
|
|
|
struct headerStats *stats = &ct->stats;
|
|
struct headerList *headerlist = ct->headerlist[arch];
|
|
int altrepository = ct->repository_level;
|
|
|
|
stats->headercount[arch] = 0;
|
|
stats->headersize[arch] = 0;
|
|
currheaderlist = headerlist;
|
|
while (currheaderlist) {
|
|
if (currheaderlist->sourceheader
|
|
&& currheaderlist->altrepository == altrepository) {
|
|
(stats->headercount[arch])++;
|
|
stats->headersize[arch] += currheaderlist->size;
|
|
}
|
|
currheaderlist = currheaderlist->next;
|
|
}
|
|
|
|
stats->headerlistvec[arch] =
|
|
malloc(sizeof(struct headerList *) * stats->headercount[arch]);
|
|
if (!stats->headerlistvec) {
|
|
return 1;
|
|
}
|
|
|
|
currheaderlist = headerlist;
|
|
c = 0;
|
|
while (currheaderlist) {
|
|
if (currheaderlist->sourceheader
|
|
&& currheaderlist->altrepository ==
|
|
altrepository) {
|
|
stats->headerlistvec[arch][c] = currheaderlist;
|
|
c++;
|
|
}
|
|
currheaderlist = currheaderlist->next;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
generateHeaderSourceStats(struct configTag *ct)
|
|
{
|
|
int altrepository = ct->repository_level;
|
|
struct headerSourceList *currheadersourcelist;
|
|
struct headerSourceList *headersourcelist = ct->headersourcelist;
|
|
struct headerStats *stats = &ct->stats;
|
|
int c;
|
|
struct changeLog *currchangelog;
|
|
|
|
stats->headersourcecount = 0;
|
|
stats->headersourcesize = 0;
|
|
currheadersourcelist = headersourcelist;
|
|
while (currheadersourcelist) {
|
|
if (currheadersourcelist->altrepository == altrepository) {
|
|
(stats->headersourcecount)++;
|
|
stats->headersourcesize += currheadersourcelist->size;
|
|
}
|
|
currheadersourcelist = currheadersourcelist->next;
|
|
}
|
|
|
|
stats->headersourcelistvec =
|
|
malloc(sizeof(struct headerSourceList *) *
|
|
stats->headersourcecount);
|
|
if (!stats->headersourcelistvec) {
|
|
return 1;
|
|
}
|
|
|
|
currheadersourcelist = headersourcelist;
|
|
c = 0;
|
|
ct->stats.changelog_total = 0;
|
|
|
|
while (currheadersourcelist) {
|
|
if (currheadersourcelist->altrepository == altrepository) {
|
|
stats->headersourcelistvec[c] = currheadersourcelist;
|
|
c++;
|
|
if (currheadersourcelist->packager &&
|
|
(currheadersourcelist->packager->role & PACKAGER_ROLE_MAINTAINER)) {
|
|
currheadersourcelist->packager->packages_count++;
|
|
}
|
|
|
|
currchangelog = currheadersourcelist->changelog;
|
|
|
|
|
|
while (currchangelog) {
|
|
ct->stats.changelog_total++;
|
|
if (currchangelog->pkg) {
|
|
currchangelog->pkg->changes_count++;
|
|
}
|
|
currchangelog = currchangelog->next;
|
|
}
|
|
|
|
}
|
|
currheadersourcelist = currheadersourcelist->next;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* this function should filter only RPM files
|
|
* fixme: it currently just filters files from other entities */
|
|
int
|
|
rpmselector(const struct dirent *entry)
|
|
{
|
|
char *ptr;
|
|
|
|
ptr = strstr(entry->d_name, ".rpm");
|
|
|
|
if (entry->d_type != DT_REG) return 0; /* skip if not a file */
|
|
|
|
if (ptr == NULL) {
|
|
logmsg(LOG_WARNING,"file %s has not rpm extension; skipping.",entry->d_name);
|
|
return 0;
|
|
}
|
|
|
|
if (strstr(entry->d_name, ".src.rpm")) {
|
|
logmsg(LOG_WARNING,"file %s looks like a source RPM; skipping.",entry->d_name);
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
sourcerpmselector(const struct dirent *entry)
|
|
{
|
|
char *ptr;
|
|
|
|
ptr = strstr(entry->d_name, ".src.rpm");
|
|
|
|
if (entry->d_type != DT_REG) return 0; /* skip if not a file */
|
|
|
|
if (ptr == NULL) {
|
|
logmsg(LOG_WARNING,"file %s has not src.rpm extension; skipping.",entry->d_name);
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
long providedListCount[ARCHS_MAX];
|
|
|
|
void
|
|
cleanProvidedListIndex(struct configTag *ct, int arch)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < PROVIDEDLIST_IDX_SIZE; i++)
|
|
ct->providedlist_idx[arch][i]=NULL;
|
|
|
|
providedListCount[arch] = 0;
|
|
ct->filetree[arch]=NULL;
|
|
}
|
|
|
|
void
|
|
createProvidedListIndex(struct providedList* *idx, int arch) {
|
|
int i, step = providedListCount[arch]/PROVIDEDLIST_IDX_SIZE;
|
|
int curridx = 1;
|
|
struct providedList *currprovided = idx[0];
|
|
|
|
if (providedListCount[arch] > PROVIDEDLIST_IDX_SIZE) {
|
|
while (currprovided && curridx < PROVIDEDLIST_IDX_SIZE) {
|
|
for (i = 0; i < step; i++)
|
|
currprovided = currprovided->next;
|
|
idx[curridx] = currprovided;
|
|
curridx++;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
static long providedListId = 0;
|
|
|
|
struct providedList*
|
|
findOrCreateProvidedListEntry(struct providedList* *idx,
|
|
char* findname, int create, int arch)
|
|
{
|
|
struct providedList *newprovided, *currprovided, *prevprovided = NULL;
|
|
int c = 0, i;
|
|
int idxbot = 0, idxtop;
|
|
|
|
if (idx[1]) {
|
|
idxtop = PROVIDEDLIST_IDX_SIZE;
|
|
while (idxtop-idxbot > 1) {
|
|
i = (idxtop + idxbot) / 2;
|
|
if (! idx[i]) idxtop = i;
|
|
else {
|
|
c = strcmp(idx[i]->name,findname);
|
|
if (c < 0) idxbot = i;
|
|
else if (c > 0) idxtop = i;
|
|
else { idxbot = i-1; idxtop = i; }
|
|
}
|
|
}
|
|
// printf("idxbot=%d idxtop=%d %s %s\n",idxbot,idxtop,idx[idxbot]->name,findname);
|
|
}
|
|
|
|
currprovided = idx[idxbot];
|
|
while (currprovided && ((c=strcmp(currprovided->name,findname)) < 0)) {
|
|
prevprovided = currprovided;
|
|
currprovided = currprovided->next;
|
|
}
|
|
|
|
if ((!currprovided) || (c > 0)) {
|
|
if (!create) return NULL;
|
|
providedListCount[arch]++;
|
|
newprovided = malloc(sizeof(struct providedList));
|
|
if (prevprovided) {
|
|
newprovided->next = prevprovided->next;
|
|
prevprovided->next = newprovided;
|
|
} else {
|
|
idx[0]=newprovided;
|
|
newprovided->next = currprovided;
|
|
}
|
|
newprovided->provider = NULL;
|
|
newprovided->numproviders = 0;
|
|
newprovided->numbuildproviders = 0;
|
|
newprovided->buildprovider = NULL;
|
|
newprovided->name = strdup(findname);
|
|
newprovided->id = ++providedListId;
|
|
return newprovided;
|
|
}
|
|
|
|
return currprovided;
|
|
}
|
|
|
|
struct fileTree*
|
|
findOrCreateFileTreeBrother(struct fileTree* *first, char* findname, int arch)
|
|
{
|
|
static long id[ARCHS_MAX] = { 0, 0, 0, 0, 0};
|
|
struct fileTree *newdir, *currdir, *prevdir = NULL;
|
|
int c = 0;
|
|
|
|
currdir = *first;
|
|
|
|
while (currdir &&
|
|
((c=strcmp(currdir->name,findname)) < 0)) {
|
|
prevdir = currdir;
|
|
currdir = currdir->next;
|
|
}
|
|
|
|
if ((!currdir) || (c > 0)) {
|
|
// dirListCount++;
|
|
newdir = malloc(sizeof(struct fileTree));
|
|
newdir->firstchild = NULL;
|
|
newdir->provider = NULL;
|
|
newdir->numproviders = 0;
|
|
newdir->parent = NULL;
|
|
newdir->id = id[arch]++;
|
|
|
|
if (prevdir) {
|
|
newdir->next = prevdir->next;
|
|
prevdir->next = newdir;
|
|
} else {
|
|
*first = newdir;
|
|
newdir->next = currdir;
|
|
}
|
|
newdir->name = strdup(findname);
|
|
return newdir;
|
|
}
|
|
return currdir;
|
|
}
|
|
|
|
|
|
struct fileTree*
|
|
findOrCreateFileTreeEntry(struct fileTree* *first, char* findname, int arch)
|
|
{
|
|
struct fileTree *currdir,*prevdir=NULL;
|
|
char *pstart,*pend;
|
|
char f[PATH_MAX];
|
|
int l;
|
|
|
|
currdir = *first;
|
|
pstart = &(findname[1]); /* skip trailing slash */
|
|
pend = &(findname[1]);
|
|
l = strlen(findname);
|
|
|
|
while (pend-findname < l) {
|
|
pend=strchr(pstart,'/');
|
|
if (pend == 0) pend=findname+l; /* not final slash, it should be a file */
|
|
|
|
strncpy(f,pstart,pend-pstart);
|
|
f[pend-pstart]='\0';
|
|
|
|
if (prevdir) {
|
|
currdir = findOrCreateFileTreeBrother(&prevdir->firstchild,f,arch);
|
|
currdir->parent = prevdir;
|
|
}
|
|
else
|
|
currdir = findOrCreateFileTreeBrother(first,f,arch);
|
|
|
|
if (!*first)
|
|
*first = currdir;
|
|
prevdir = currdir;
|
|
pstart=pend+1;
|
|
}
|
|
return currdir;
|
|
}
|
|
|
|
struct fileUserList*
|
|
findOrCreateFileUserListEntry(struct fileUserList* *first,char* name, int arch)
|
|
{
|
|
static long id[ARCHS_MAX] = { 0, 0, 0, 0, 0 };
|
|
struct fileUserList *curr = *first, *prev = NULL, *newf = NULL;
|
|
int i;
|
|
|
|
while (curr && (i=strcmp(curr->name,name)) < 0) {
|
|
prev = curr;
|
|
curr = curr->next;
|
|
}
|
|
if (curr && (i == 0)) return curr;
|
|
newf = malloc(sizeof(struct fileUserList));
|
|
newf->name = strdup(name);
|
|
newf->id = ++id[arch];
|
|
if (prev) prev->next = newf; else *first = newf;
|
|
if (curr) newf->next = curr; else newf->next = NULL;
|
|
if (!*first) *first = newf;
|
|
return newf;
|
|
}
|
|
|
|
struct fileGroupList*
|
|
findOrCreateFileGroupListEntry(struct fileGroupList* *first,char* name, int arch)
|
|
{
|
|
static long id[ARCHS_MAX] = { 0, 0, 0, 0, 0 };
|
|
struct fileGroupList *curr = *first, *prev = NULL, *newf = NULL;
|
|
int i;
|
|
|
|
while (curr && ((i=strcmp(curr->name,name)) < 0)) {
|
|
prev = curr;
|
|
curr = curr->next;
|
|
}
|
|
if (curr && (i == 0)) return curr;
|
|
newf = malloc(sizeof(struct fileGroupList));
|
|
newf->name = strdup(name);
|
|
newf->id = ++id[arch];
|
|
if (prev) prev->next = newf; else *first = newf;
|
|
if (curr) newf->next = curr; else newf->next = NULL;
|
|
if (!*first) *first = newf;
|
|
return newf;
|
|
}
|
|
|
|
struct repoData {
|
|
char *dir;
|
|
char *primary;
|
|
xmlDoc *primary_doc;
|
|
long primary_size;
|
|
char *filelists;
|
|
xmlDoc *filelists_doc;
|
|
long filelists_size;
|
|
char *other;
|
|
xmlDoc *other_doc;
|
|
long other_size;
|
|
};
|
|
|
|
xmlDoc* parseRepodataXmlGz(char* filename, long size_open) {
|
|
xmlDoc *doc = NULL;
|
|
gzFile gzIn;
|
|
|
|
gzIn = gzopen(filename, "r");
|
|
if (gzIn == NULL) {
|
|
logmsg(LOG_ERROR, "error opening file: %", filename);
|
|
} else {
|
|
char *buffer = malloc(size_open);
|
|
gzread(gzIn, buffer, size_open);
|
|
gzclose(gzIn);
|
|
doc = xmlReadMemory(buffer, size_open, "noname.xml", NULL, 0);
|
|
free(buffer);
|
|
}
|
|
return doc;
|
|
}
|
|
|
|
struct repoData* getRepodata(char *repodata_url, char *arch) {
|
|
gboolean ret;
|
|
LrHandle *h;
|
|
LrResult *r;
|
|
LrYumRepoMd *repomd;
|
|
char *download_list[] = LR_RPMMD_BASEXML;
|
|
char *urls[] = { NULL, NULL };
|
|
GError *tmp_err = NULL;
|
|
struct repoData *repodata;
|
|
|
|
urls[0] = malloc(PATH_MAX);
|
|
if (!arch)
|
|
snprintf(urls[0], PATH_MAX, "%s/SRPMS.base/", repodata_url);
|
|
else
|
|
snprintf(urls[0], PATH_MAX, "%s/RPMS.%s/", repodata_url, arch);
|
|
|
|
logmsg(LOG_DEBUG, "fetching repodata from %s...", urls[0]);
|
|
|
|
h = lr_handle_init();
|
|
r = lr_result_init();
|
|
|
|
lr_handle_setopt(h, NULL, LRO_URLS, urls);
|
|
lr_handle_setopt(h, NULL, LRO_REPOTYPE, LR_YUMREPO);
|
|
lr_handle_setopt(h, NULL, LRO_YUMDLIST, download_list);
|
|
|
|
// Create temporary directory
|
|
char template[] = "/tmp/distromatic.tmp.XXXXXX";
|
|
char *dir_name = mkdtemp(template);
|
|
if(dir_name == NULL)
|
|
{
|
|
perror("mkdtemp failed: ");
|
|
return NULL;
|
|
}
|
|
repodata = malloc(sizeof(struct repoData));
|
|
repodata->dir = strdup(dir_name);
|
|
lr_handle_setopt(h, NULL, LRO_DESTDIR, dir_name);
|
|
|
|
ret = lr_handle_perform(h, r, &tmp_err);
|
|
if (!ret) {
|
|
logmsg(LOG_ERROR, "cannot get repodata from %s: %d: %s\n",
|
|
urls[0], tmp_err->code, tmp_err->message);
|
|
g_error_free(tmp_err);
|
|
lr_result_free(r);
|
|
lr_handle_free(h);
|
|
return NULL;
|
|
}
|
|
|
|
lr_result_getinfo(r, &tmp_err, LRR_YUM_REPOMD, &repomd);
|
|
|
|
if (!tmp_err) {
|
|
char filename[PATH_MAX];
|
|
for (GSList *elem = repomd->records; elem; elem = g_slist_next(elem)) {
|
|
LrYumRepoMdRecord *rec = (LrYumRepoMdRecord *) elem->data;
|
|
if (!strcmp(rec->type, "primary")) {
|
|
repodata->primary = strdup(rec->location_href);
|
|
snprintf(filename, PATH_MAX, "%s/%s", repodata->dir,
|
|
repodata->primary);
|
|
repodata->primary_doc = parseRepodataXmlGz(filename,
|
|
rec->size_open);
|
|
} else if (!strcmp(rec->type, "filelists")) {
|
|
repodata->filelists = strdup(rec->location_href);
|
|
snprintf(filename, PATH_MAX, "%s/%s", repodata->dir,
|
|
repodata->filelists);
|
|
repodata->filelists_doc = parseRepodataXmlGz(filename,
|
|
rec->size_open);
|
|
} else if (!strcmp(rec->type, "other")) {
|
|
repodata->other = strdup(rec->location_href);
|
|
snprintf(filename, PATH_MAX, "%s/%s", repodata->dir,
|
|
repodata->other);
|
|
repodata->other_doc = parseRepodataXmlGz(filename,
|
|
rec->size_open);
|
|
}
|
|
}
|
|
}
|
|
|
|
lr_result_free(r);
|
|
lr_handle_free(h);
|
|
|
|
return repodata;
|
|
}
|
|
|
|
void cleanRepodata(struct repoData *repodata) {
|
|
char filename[PATH_MAX];
|
|
|
|
if (!repodata) return;
|
|
|
|
if (repodata->dir) {
|
|
if (repodata->primary) {
|
|
snprintf(filename, PATH_MAX, "%s/%s", repodata->dir,
|
|
repodata->primary);
|
|
unlink(filename);
|
|
free(repodata->primary);
|
|
xmlFreeDoc(repodata->primary_doc);
|
|
}
|
|
if (repodata->filelists) {
|
|
snprintf(filename, PATH_MAX, "%s/%s", repodata->dir,
|
|
repodata->filelists);
|
|
unlink(filename);
|
|
free(repodata->filelists);
|
|
xmlFreeDoc(repodata->filelists_doc);
|
|
}
|
|
if (repodata->other) {
|
|
snprintf(filename, PATH_MAX, "%s/%s", repodata->dir,
|
|
repodata->other);
|
|
unlink(filename);
|
|
free(repodata->other);
|
|
xmlFreeDoc(repodata->other_doc);
|
|
}
|
|
snprintf(filename, PATH_MAX, "%s/repodata/repomd.xml", repodata->dir);
|
|
unlink(filename);
|
|
snprintf(filename, PATH_MAX, "%s/repodata", repodata->dir);
|
|
rmdir(filename);
|
|
rmdir(repodata->dir);
|
|
free(repodata->dir);
|
|
}
|
|
free(repodata);
|
|
}
|
|
|
|
xmlChar* findXMLAttributeByName(xmlNode *node, char* name) {
|
|
xmlAttr* attribute = node->properties;
|
|
while(attribute && attribute->name && attribute->children)
|
|
{
|
|
if (!strcmp((char*)attribute->name, name)) {
|
|
xmlChar* value = xmlNodeListGetString(node->doc, attribute->children, 1);
|
|
return value;
|
|
}
|
|
attribute = attribute->next;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
xmlNode* findXMLPropertyByName(xmlNode *node, char* name) {
|
|
xmlNode *props_node = NULL;
|
|
|
|
for (props_node = node->children; props_node; props_node = props_node->next) {
|
|
if (props_node->type == XML_ELEMENT_NODE && !strcmp((char*)props_node->name, name))
|
|
return props_node;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
xmlNode* findXMLPackageByName(xmlNode *root_node, char* name) {
|
|
xmlNode *package_node = NULL;
|
|
xmlNode *props_node = NULL;
|
|
for (package_node = root_node->children; package_node; package_node = package_node->next) {
|
|
if (!strcmp((char*)package_node->name, "package")) {
|
|
for (props_node = package_node->children; props_node; props_node = props_node->next) {
|
|
if (props_node->type == XML_ELEMENT_NODE && !strcmp((char*)props_node->name, "name")) {
|
|
if (props_node->children && !strcmp((char*)props_node->children, name))
|
|
return package_node;
|
|
break;
|
|
}
|
|
}
|
|
xmlChar* value = findXMLAttributeByName(package_node, "name");
|
|
if (value) {
|
|
if (!strcmp((char*)value, name)) {
|
|
xmlFree(value);
|
|
return package_node;
|
|
}
|
|
xmlFree(value);
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int XMLFlagToInt(char *flag) {
|
|
if (!flag)
|
|
return RPMSENSE_ANY;
|
|
else if (!strcmp(flag, "EQ"))
|
|
return RPMSENSE_EQUAL;
|
|
else if (!strcmp(flag, "LT"))
|
|
return RPMSENSE_LESS;
|
|
else if (!strcmp(flag, "LE"))
|
|
return RPMSENSE_EQUAL | RPMSENSE_LESS;
|
|
else if (!strcmp(flag, "GT"))
|
|
return RPMSENSE_GREATER;
|
|
else if (!strcmp(flag, "GE"))
|
|
return RPMSENSE_EQUAL | RPMSENSE_GREATER;
|
|
return RPMSENSE_ANY;
|
|
}
|
|
|
|
void getXMLPackageFiles(xmlNode *parent, uint **type, char ***path, int *count) {
|
|
|
|
*count = xmlChildElementCount(parent) - 1; // first child node is "version"
|
|
if (*count == 0) {
|
|
*type = NULL;
|
|
*path = NULL;
|
|
return;
|
|
}
|
|
*type = malloc(sizeof(uint*) * (*count));
|
|
*path = malloc(sizeof(char*) * (*count+1));
|
|
|
|
int i = 0;
|
|
for (xmlNode *entry=parent->children; entry; entry=entry->next) {
|
|
if (entry->type == XML_ELEMENT_NODE && !strcmp((char*)entry->name, "file")) {
|
|
(*path)[i] = strdup((char*)entry->children->content);
|
|
char* ftype = (char*)findXMLAttributeByName(entry, "type");
|
|
if (!ftype)
|
|
(*type)[i] = 0;
|
|
else if (!strcmp(ftype, "dir"))
|
|
(*type)[i] = 1;
|
|
else if (!strcmp(ftype, "ghost"))
|
|
(*type)[i] = 2;
|
|
i++;
|
|
}
|
|
}
|
|
// Null terminated list
|
|
(*path)[i] = NULL;
|
|
}
|
|
|
|
void getXMLPackageChangelog(xmlNode *parent,
|
|
uint_32 **changelogtime, char ***changelogrelease,
|
|
char ***changelogtext, int *count) {
|
|
|
|
*count = xmlChildElementCount(parent) - 1;
|
|
if (*count == 0) {
|
|
*changelogtime = NULL;
|
|
*changelogrelease = NULL;
|
|
*changelogtext = NULL;
|
|
return;
|
|
}
|
|
|
|
*changelogtime = malloc(sizeof(uint_32*) * *count);
|
|
*changelogrelease = malloc(sizeof(char*) * *count);
|
|
*changelogtext = malloc(sizeof(char*) * *count);
|
|
|
|
int i = *count -1;
|
|
for (xmlNode *entry=parent->children; entry; entry=entry->next) {
|
|
if (entry->type == XML_ELEMENT_NODE && !strcmp((char*)entry->name, "changelog")) {
|
|
char *tmp = (char*)findXMLAttributeByName(entry, "date");
|
|
(*changelogtime)[i] = atoi(tmp);
|
|
free(tmp);
|
|
(*changelogrelease)[i] = (char*)findXMLAttributeByName(entry, "author");
|
|
(*changelogtext)[i] = (char*)entry->children->content;
|
|
i--;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void getXMLPackageNFV(xmlNode *parent, char ***name,
|
|
uint_32 **flags, char ***version, int *count) {
|
|
char buf[PATH_MAX];
|
|
|
|
*count = xmlChildElementCount(parent);
|
|
if (*count == 0) {
|
|
*name = NULL;
|
|
*flags = NULL;
|
|
*version = NULL;
|
|
return;
|
|
}
|
|
*name = malloc(sizeof(char*) * *count);
|
|
*flags = malloc(sizeof(uint_32) * *count);
|
|
*version = malloc(sizeof(char*) * *count);
|
|
|
|
int i = 0;
|
|
for (xmlNode *entry=parent->children; entry; entry=entry->next) {
|
|
if (entry->type == XML_ELEMENT_NODE) {
|
|
if (i >= *count) {
|
|
logmsg(LOG_ERROR,"getXMLPackageNFV: count (%d) is less than found XML elements; skipping.",
|
|
*count);
|
|
return;
|
|
}
|
|
(*name)[i] = (char*)findXMLAttributeByName(entry, "name");
|
|
(*flags)[i] = XMLFlagToInt(
|
|
(char*)findXMLAttributeByName(entry, "flags"));
|
|
buf[0] = '\0';
|
|
if ((*flags)[i] != RPMSENSE_ANY) {
|
|
char *epoch = (char*)findXMLAttributeByName(entry, "epoch");
|
|
char *ver = (char*)findXMLAttributeByName(entry, "ver");
|
|
char *rel = (char*)findXMLAttributeByName(entry, "rel");
|
|
if (epoch && ver && rel) {
|
|
snprintf(buf, PATH_MAX,"%s:%s-%s", epoch, ver, rel);
|
|
free(epoch);
|
|
free(ver);
|
|
free(rel);
|
|
} else if (epoch && ver) {
|
|
snprintf(buf, PATH_MAX,"%s:%s", epoch, ver);
|
|
free(epoch);
|
|
free(ver);
|
|
}
|
|
}
|
|
(*version)[i] = strdup(buf);
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
|
|
static long sourceid = 0;
|
|
struct headerSourceList *currheadersourcelist = NULL;
|
|
|
|
void addNewToSourceHeaderList(struct headerSourceList *newheadersourcelist,
|
|
struct configTag *ct, int altrepository) {
|
|
|
|
struct headerSourceList *prevheadersourcelist;
|
|
|
|
char warning[PATH_MAX];
|
|
|
|
/* if main repository (altrepository=0) packages are inserted sequentially
|
|
* otherwise the list is scanned and packages are inserted alphabetically */
|
|
if (!altrepository) {
|
|
if (currheadersourcelist) {
|
|
currheadersourcelist->next = newheadersourcelist;
|
|
}
|
|
currheadersourcelist = newheadersourcelist;
|
|
} else { /* altrepository */
|
|
currheadersourcelist = ct->headersourcelist;
|
|
prevheadersourcelist = NULL;
|
|
while ((currheadersourcelist) &&
|
|
(strcmp(currheadersourcelist->name,newheadersourcelist->name) < 0)) {
|
|
prevheadersourcelist = currheadersourcelist;
|
|
currheadersourcelist = currheadersourcelist->next;
|
|
}
|
|
|
|
if ((currheadersourcelist) &&
|
|
(!strcmp(currheadersourcelist->name,newheadersourcelist->name))) {
|
|
/* the package is both in main and alternate repositories.
|
|
override main repository package */
|
|
|
|
if ((currheadersourcelist->epoch > newheadersourcelist->epoch) ||
|
|
((currheadersourcelist->epoch == newheadersourcelist->epoch) &&
|
|
(rpmvercmp(currheadersourcelist->version,
|
|
newheadersourcelist->version) > 0)) ||
|
|
((currheadersourcelist->epoch == newheadersourcelist->epoch) &&
|
|
(rpmvercmp(currheadersourcelist->version,
|
|
newheadersourcelist->version) == 0) &&
|
|
(rpmvercmp(currheadersourcelist->release,
|
|
newheadersourcelist->release) >= 0))) {
|
|
if (ct->repository_level == altrepository) {
|
|
snprintf(warning, PATH_MAX, "is older or same release of upstream package in %s (%ld:%s-%s <= %ld:%s-%s)",
|
|
ct->repository[currheadersourcelist->altrepository]->tag,
|
|
newheadersourcelist->epoch,
|
|
newheadersourcelist->version,
|
|
newheadersourcelist->release,
|
|
currheadersourcelist->epoch,
|
|
currheadersourcelist->version,
|
|
currheadersourcelist->release);
|
|
logmsg(LOG_WARNING,
|
|
"%s(source,%s): %s",
|
|
newheadersourcelist->name,
|
|
ct->repository[newheadersourcelist->altrepository]->tag,
|
|
warning);
|
|
addWarning(newheadersourcelist, warning);
|
|
}
|
|
}
|
|
newheadersourcelist->next = currheadersourcelist->next;
|
|
/* overriden package is not deallocated but referenced with currheadersourcelist->old */
|
|
newheadersourcelist->old=currheadersourcelist;
|
|
newheadersourcelist->old->updatingparent=newheadersourcelist;
|
|
} else {
|
|
/* add the new package to the list */
|
|
newheadersourcelist->next = currheadersourcelist;
|
|
}
|
|
if (prevheadersourcelist) {
|
|
prevheadersourcelist->next = newheadersourcelist;
|
|
} else {
|
|
ct->headersourcelist = newheadersourcelist;
|
|
}
|
|
} /* altrepository */
|
|
|
|
if (!ct->headersourcelist) {
|
|
/* set first pointer of the list */
|
|
ct->headersourcelist = newheadersourcelist;
|
|
}
|
|
|
|
}
|
|
|
|
int addToSourceHeaderList(struct configTag *ct, int mode, int altrepository) {
|
|
char *scanpath;
|
|
char *tmp;
|
|
struct repoData* repodata = NULL;
|
|
struct headerSourceList *newheadersourcelist;
|
|
struct dirent **namelist;
|
|
struct changeLog *changelog;
|
|
Header h;
|
|
char filepath[bufsize + 1];
|
|
int n = 0, j, arch, filenamescount, dirnamescount;
|
|
int_16 *fileflags;
|
|
char **basenames, **dirnames, **usernames, **groupnames;
|
|
const char* errstr;
|
|
int requirecount;
|
|
char **requireversion, **requirename;
|
|
uint_32 *requireflags, *dirindexes;
|
|
char warning[PATH_MAX];
|
|
rpmts ts;
|
|
|
|
currheadersourcelist = NULL;
|
|
|
|
if (altrepository == ct->repository_level) {
|
|
scanpath = ct->repository_source_dir;
|
|
if (ct->repodata_url) {
|
|
repodata = getRepodata(ct->repodata_url, NULL);
|
|
if (!repodata) return 1;
|
|
}
|
|
logmsg(LOG_DEBUG,"Scanning source packages in repository %s...", ct->tag);
|
|
} else if (altrepository == -1) {
|
|
// non-incremental mode
|
|
scanpath = ct->repository_source_dir;
|
|
altrepository = 0;
|
|
if (ct->repodata_url) {
|
|
repodata = getRepodata(ct->repodata_url, NULL);
|
|
if (!repodata) return 1;
|
|
}
|
|
logmsg(LOG_DEBUG,"Scanning source packages in repository %s...", ct->tag);
|
|
} else {
|
|
scanpath = ct->repository[altrepository]->repository_source_dir;
|
|
if (ct->repodata_url) {
|
|
repodata = getRepodata(ct->repository[altrepository]->repodata_url, NULL);
|
|
if (!repodata) return 1;
|
|
}
|
|
logmsg(LOG_DEBUG,"Scanning source packages in repository %s...", ct->repository[altrepository]->tag);
|
|
}
|
|
if (repodata) {
|
|
// Use repodata
|
|
xmlNode *filelists_node = xmlDocGetRootElement(repodata->filelists_doc)->children;
|
|
xmlNode *other_node = xmlDocGetRootElement(repodata->other_doc)->children;
|
|
for (xmlNode *package_node = xmlDocGetRootElement(repodata->primary_doc)->children;
|
|
package_node;
|
|
package_node = package_node->next,
|
|
filelists_node = filelists_node->next,
|
|
other_node = other_node->next) {
|
|
if (!strcmp((char*)package_node->name, "package")) {
|
|
char *package_name = strdup((char*)
|
|
findXMLPropertyByName(package_node, "name")->children->content);
|
|
xmlNode *version = findXMLPropertyByName(package_node, "version");
|
|
tmp = (char*)findXMLAttributeByName(version, "epoch");
|
|
int package_epoch = atoi(tmp);
|
|
free(tmp);
|
|
char *package_version = (char*)findXMLAttributeByName(version, "ver");
|
|
char *package_release = (char*)findXMLAttributeByName(version, "rel");
|
|
|
|
// Check next package for duplicates
|
|
xmlNode *next_package = package_node->next;
|
|
while (next_package && strcmp((char*)next_package->name, "package")) {
|
|
next_package = next_package->next;
|
|
}
|
|
if (next_package) {
|
|
char *next_package_name = strdup((char*)
|
|
findXMLPropertyByName(next_package, "name")->children->content);
|
|
if (!strcmp(package_name, next_package_name)) {
|
|
// Assuming that older packages come first
|
|
logmsg(LOG_WARNING,"skipping older duplicated SRPM package %s(%d:%s:%s)",
|
|
package_name, package_epoch, package_version, package_release);
|
|
free(next_package_name);
|
|
free(package_name);
|
|
free(package_version);
|
|
free(package_release);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
newheadersourcelist = malloc(sizeof(struct headerSourceList));
|
|
if (newheadersourcelist == NULL) return 1;
|
|
|
|
newheadersourcelist->next = NULL;
|
|
for (arch = 0; arch < ARCHS_MAX; arch++) {
|
|
newheadersourcelist->firstchild[arch] = NULL;
|
|
}
|
|
newheadersourcelist->updatingparent = NULL;
|
|
newheadersourcelist->altrepository = altrepository;
|
|
newheadersourcelist->firstwarning = NULL;
|
|
newheadersourcelist->firstrebuild = NULL;
|
|
newheadersourcelist->old = NULL;
|
|
newheadersourcelist->id = ++sourceid;
|
|
|
|
newheadersourcelist->name = package_name;
|
|
newheadersourcelist->epoch = package_epoch;
|
|
newheadersourcelist->version = package_version;
|
|
newheadersourcelist->release = package_release;
|
|
newheadersourcelist->summary = strdup((char*)
|
|
findXMLPropertyByName(package_node, "summary")->children->content);
|
|
newheadersourcelist->arch = strdup((char*)
|
|
findXMLPropertyByName(package_node, "arch")->children->content);
|
|
if (findXMLPropertyByName(package_node, "description")->children) {
|
|
newheadersourcelist->description = strdup((char*)
|
|
findXMLPropertyByName(package_node, "description")->children->content);
|
|
} else {
|
|
logmsg(LOG_WARNING, "%s(source, %s): description field is empty",
|
|
newheadersourcelist->name, ct->tag);
|
|
newheadersourcelist->description = strdup("");
|
|
}
|
|
char* packager = strdup((char*)
|
|
findXMLPropertyByName(package_node, "packager")->children->content);
|
|
if (!packager) {
|
|
logmsg(LOG_WARNING,"missing packager definition in package %s.",newheadersourcelist->name);
|
|
newheadersourcelist->packager = NULL;
|
|
} else {
|
|
newheadersourcelist->packager = getPackagerByName(packager,1);
|
|
if (!newheadersourcelist->packager) {
|
|
logmsg(LOG_WARNING,"cannot create '%s' packager for package %s.",
|
|
packager, newheadersourcelist->name);
|
|
}
|
|
free(packager);
|
|
}
|
|
xmlNode *format = findXMLPropertyByName(package_node, "format");
|
|
newheadersourcelist->group = strdup((char*)
|
|
findXMLPropertyByName(format, "group")->children->content);
|
|
newheadersourcelist->license = strdup((char*)
|
|
findXMLPropertyByName(format, "license")->children->content);
|
|
newheadersourcelist->url = strdup((char*)
|
|
findXMLPropertyByName(package_node, "url")->children->content);
|
|
if (!newheadersourcelist->url)
|
|
logmsg(LOG_WARNING,"missing URL definition for package %s.",
|
|
newheadersourcelist->name);
|
|
xmlNode *ptime = findXMLPropertyByName(package_node, "time");
|
|
tmp = (char*)findXMLAttributeByName(ptime, "build");
|
|
newheadersourcelist->buildtime = atoi(tmp);
|
|
free(tmp);
|
|
xmlNode *psize = findXMLPropertyByName(package_node, "size");
|
|
tmp = (char*)findXMLAttributeByName(psize, "package");
|
|
newheadersourcelist->size = atoi(tmp);
|
|
free(tmp);
|
|
// FIXME: information missing from repodata
|
|
newheadersourcelist->buildarchs = NULL;
|
|
newheadersourcelist->excludearch = NULL;
|
|
newheadersourcelist->patch = NULL;
|
|
|
|
// Requires
|
|
getXMLPackageNFV(findXMLPropertyByName(format, "requires"),
|
|
&requirename, &requireflags, &requireversion, &requirecount);
|
|
newheadersourcelist->require = malloc(requirecount *
|
|
sizeof(struct Require *));
|
|
for (j=0; j < requirecount; j++) {
|
|
newheadersourcelist->require[j] = malloc(sizeof(struct Require));
|
|
newheadersourcelist->require[j]->name = requirename[j];
|
|
newheadersourcelist->require[j]->flags = requireflags[j];
|
|
newheadersourcelist->require[j]->version = requireversion[j];
|
|
newheadersourcelist->require[j]->resolved = NULL;
|
|
}
|
|
newheadersourcelist->requirecount = requirecount;
|
|
|
|
// Files
|
|
getXMLPackageFiles(filelists_node, &fileflags, &basenames, &filenamescount);
|
|
newheadersourcelist->source = basenames;
|
|
newheadersourcelist->filenamecount = 0;
|
|
|
|
// Changelog
|
|
if (mode & GENHEADER_CHANGELOG) {
|
|
int changelogcount;
|
|
uint_32 *changelogtime;
|
|
char **changelogrelease;
|
|
char **changelogtext;
|
|
getXMLPackageChangelog(other_node, &changelogtime, &changelogrelease,
|
|
&changelogtext, &changelogcount);
|
|
|
|
changelog = getPackageChangelog(changelogtime, changelogrelease,
|
|
changelogtext, changelogcount, newheadersourcelist);
|
|
|
|
while (changelog) {
|
|
if ((!changelog->pkg) || (!changelog->text)) {
|
|
snprintf(warning, PATH_MAX, "missing changelog name and/or text");
|
|
logmsg(LOG_WARNING,
|
|
"%s: missing changelog name and/or text",
|
|
newheadersourcelist->name);
|
|
addWarning(newheadersourcelist, warning);
|
|
}
|
|
changelog = changelog->next;
|
|
}
|
|
} else {
|
|
newheadersourcelist->changelog = NULL;
|
|
}
|
|
|
|
// Add newheadersourcelist to sourceheaderlist
|
|
addNewToSourceHeaderList(newheadersourcelist, ct, altrepository);
|
|
}
|
|
}
|
|
cleanRepodata(repodata);
|
|
} else {
|
|
// Scan local repository dir
|
|
ts = rpmtsCreate();
|
|
assert(scanpath != NULL);
|
|
memcpy(filepath, scanpath, strlen(scanpath) + 1);
|
|
logmsg(LOG_DEBUG, "scanning source directory '%s' (%d)", scanpath, altrepository);
|
|
n = scansdir(scanpath, &namelist, sourcerpmselector, scanrpmnamecmp);
|
|
if (n < 0) {
|
|
errstr = strerror(errno);
|
|
logmsg(LOG_ERROR, "cannot scan directory '%s' (%s)", scanpath, errstr);
|
|
return 1;
|
|
}
|
|
int cnt;
|
|
for (cnt = 0; cnt < n; ++cnt) {
|
|
/* check for duplicates */
|
|
if ((cnt < n - 1) &&
|
|
(!rpmnamecmp(namelist[cnt]->d_name,namelist[cnt+1]->d_name,0))) {
|
|
logmsg(LOG_WARNING,"skipping old SRPM package %s",namelist[cnt]->d_name);
|
|
cnt++;
|
|
}
|
|
strcpy(&filepath[strlen(scanpath)], namelist[cnt]->d_name);
|
|
logmsg(LOG_DEBUG, "getting header for %s", filepath);
|
|
|
|
if (getHeader(&ts, filepath, &h)) {
|
|
errstr = strerror(errno);
|
|
logmsg(LOG_WARNING, "%s: unable to read header (%s); skipping.",
|
|
namelist[cnt]->d_name, errstr);
|
|
} else {
|
|
getPackageFiles(h, &dirindexes, &dirnames, &dirnamescount,
|
|
&basenames, &filenamescount, &usernames, &groupnames, &fileflags);
|
|
|
|
newheadersourcelist = malloc(sizeof(struct headerSourceList));
|
|
if (newheadersourcelist == NULL) return 1;
|
|
|
|
newheadersourcelist->next = NULL;
|
|
for (arch = 0; arch < ARCHS_MAX; arch++) {
|
|
newheadersourcelist->firstchild[arch] = NULL;
|
|
}
|
|
newheadersourcelist->updatingparent = NULL;
|
|
newheadersourcelist->altrepository = altrepository;
|
|
newheadersourcelist->firstwarning = NULL;
|
|
newheadersourcelist->firstrebuild = NULL;
|
|
newheadersourcelist->old = NULL;
|
|
newheadersourcelist->id = ++sourceid;
|
|
|
|
getPackageInfoIntoHeaderSourceList(h, newheadersourcelist);
|
|
|
|
getPackageRequires(h, &requirename, &requireflags, &requireversion,
|
|
&requirecount);
|
|
|
|
newheadersourcelist->dirindex = malloc(sizeof(int) * filenamescount);
|
|
if (!newheadersourcelist->dirindex) return 1;
|
|
|
|
memcpy(newheadersourcelist->dirindex, dirindexes,
|
|
sizeof(int) * filenamescount);
|
|
newheadersourcelist->dirname =
|
|
(char **) dupnargv(dirnames, dirnamescount);
|
|
newheadersourcelist->basename =
|
|
(char **) dupnargv(basenames, filenamescount);
|
|
newheadersourcelist->filenamecount = filenamescount;
|
|
newheadersourcelist->require = malloc(requirecount *
|
|
sizeof(struct Require *));
|
|
for (j=0; j < requirecount; j++) {
|
|
newheadersourcelist->require[j] = malloc(sizeof(struct Require));
|
|
newheadersourcelist->require[j]->name = requirename[j];
|
|
newheadersourcelist->require[j]->flags = requireflags[j];
|
|
newheadersourcelist->require[j]->version = requireversion[j];
|
|
newheadersourcelist->require[j]->resolved = NULL;
|
|
}
|
|
newheadersourcelist->requirecount = requirecount;
|
|
|
|
if (mode & GENHEADER_CHANGELOG) {
|
|
int count;
|
|
uint_32 *changelogtime = headerGetUIntArrayEntry(h,
|
|
RPMTAG_CHANGELOGTIME, &count);
|
|
char **changelogrelease = headerGetStringArrayEntry(h,
|
|
RPMTAG_CHANGELOGNAME, &count);
|
|
char **changelogtext = headerGetStringArrayEntry(h,
|
|
RPMTAG_CHANGELOGTEXT, &count);
|
|
|
|
changelog = getPackageChangelog(changelogtime, changelogrelease,
|
|
changelogtext, count, newheadersourcelist);
|
|
while (changelog) {
|
|
if ((!changelog->pkg) || (!changelog->text)) {
|
|
snprintf(warning, PATH_MAX, "missing changelog name and/or text");
|
|
logmsg(LOG_WARNING,
|
|
"%s: missing changelog name and/or text",
|
|
newheadersourcelist->name);
|
|
addWarning(newheadersourcelist, warning);
|
|
}
|
|
changelog = changelog->next;
|
|
}
|
|
} else {
|
|
newheadersourcelist->changelog = NULL;
|
|
}
|
|
|
|
addNewToSourceHeaderList(newheadersourcelist, ct, altrepository);
|
|
|
|
(void) headerFree(h);
|
|
} // if getHeader()
|
|
free(namelist[cnt]);
|
|
} // for
|
|
free(namelist);
|
|
rpmtsFree(ts);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
generateSourceHeaderList(struct configTag *ct, int mode, int incremental)
|
|
{
|
|
int i;
|
|
|
|
if (incremental) {
|
|
for (i = 0; i <= ct->repository_level; i++) {
|
|
if (ct->repository[i]) {
|
|
if (addToSourceHeaderList(ct, mode, i)) {
|
|
logmsg(LOG_ERROR,"Error scanning SRPMs repository");
|
|
return 1;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
if (addToSourceHeaderList(ct, mode, -1)) {
|
|
logmsg(LOG_ERROR,"Error scanning SRPMs repository");
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int addNewToHeaderList(struct headerList **currheaderlist,
|
|
struct headerList *newheaderlist, struct configTag *ct,
|
|
int altrepository, int arch) {
|
|
|
|
struct headerList *currbrother;
|
|
|
|
if (!newheaderlist->sourcename) {
|
|
logmsg(LOG_WARNING,
|
|
"sourcename undefined in RPM %s, it might be a source RPM with wrong filename; skipping package.",
|
|
newheaderlist->name);
|
|
newheaderlist->sourceheader = NULL;
|
|
free(newheaderlist);
|
|
return -1;
|
|
} else {
|
|
if (getPackageNameFromFile(newheaderlist->sourcename)) {
|
|
logmsg(LOG_WARNING,
|
|
"file %s doesn't have a standard format; skipping package.");
|
|
newheaderlist->sourceheader = NULL;
|
|
free(newheaderlist);
|
|
return -1;
|
|
} else {
|
|
newheaderlist->sourceheader =
|
|
findSourcePackage(ct->headersourcelist,
|
|
newheaderlist->sourcename,
|
|
newheaderlist->version,
|
|
newheaderlist->release,
|
|
altrepository);
|
|
}
|
|
}
|
|
if (newheaderlist->sourceheader) {
|
|
if (!newheaderlist->sourceheader->firstchild[arch]) {
|
|
newheaderlist->sourceheader->firstchild[arch] = newheaderlist;
|
|
} else {
|
|
currbrother =
|
|
newheaderlist->sourceheader->firstchild[arch];
|
|
while (currbrother->nextbrother) {
|
|
currbrother = currbrother->nextbrother;
|
|
}
|
|
currbrother->nextbrother = newheaderlist;
|
|
}
|
|
newheaderlist->recursed = 0;
|
|
if (*currheaderlist) {
|
|
(*currheaderlist)->next = newheaderlist;
|
|
}
|
|
*currheaderlist = newheaderlist;
|
|
|
|
if (!ct->headerlist[arch]) {
|
|
/* set first pointer of the list */
|
|
ct->headerlist[arch] = newheaderlist;
|
|
}
|
|
} else if (newheaderlist->sourcename) /* missing source header */ {
|
|
if ((!newheaderlist->sourceheader) ||
|
|
(newheaderlist->sourceheader->altrepository) <= altrepository) {
|
|
logmsg(LOG_WARNING,"%s(%s,%s): missing SRPM %s-%s-%s; skipping.",
|
|
newheaderlist->name,
|
|
ct->arch[arch],
|
|
ct->repository[altrepository]->tag,
|
|
newheaderlist->sourcename,
|
|
newheaderlist->version, newheaderlist->release);
|
|
free(newheaderlist);
|
|
return -1;
|
|
}
|
|
} // if newheaderlist->sourceheader
|
|
|
|
return 0;
|
|
}
|
|
|
|
char* advanceXMLPackageNode(xmlNode **primary_node, xmlNode **filelists_node) {
|
|
|
|
char* currname;
|
|
|
|
if (*primary_node) {
|
|
*primary_node = (*primary_node)->next;
|
|
*filelists_node = (*filelists_node)->next;
|
|
}
|
|
while (*primary_node && strcmp((char*)(*primary_node)->name, "package")) {
|
|
*primary_node = (*primary_node)->next;
|
|
*filelists_node = (*filelists_node)->next;
|
|
}
|
|
if (*primary_node) {
|
|
currname = strdup((char*)
|
|
findXMLPropertyByName(*primary_node, "name")->children->content);
|
|
return currname;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Reads all headers and generates a structure based on struct headerList
|
|
*/
|
|
int generateHeaderList(struct configTag* ct, int arch, int incremental) {
|
|
|
|
struct repoData* repodata[ALT_REPS_MAX + 1];
|
|
xmlNode *primary_node[ALT_REPS_MAX + 1], *filelists_node[ALT_REPS_MAX + 1];
|
|
char *currnames[ALT_REPS_MAX + 1];
|
|
char nextname[bufsize + 1];
|
|
char *tmp;
|
|
|
|
char scanpath[bufsize + 1], *altscanpath[ALT_REPS_MAX];
|
|
char *scantag, *altscantag[ALT_REPS_MAX];
|
|
int cnt = 0, altcnt[ALT_REPS_MAX];
|
|
struct headerList *currheaderlist, *newheaderlist;
|
|
struct providedList *provided;
|
|
struct headerList ** newprovider;
|
|
struct dirent **namelist, **altnamelist[ALT_REPS_MAX];
|
|
Header h;
|
|
char filepath[bufsize + 1], currname[bufsize + 1];
|
|
char *filename=NULL;
|
|
long i ,j , k, n=0, altn[ALT_REPS_MAX];
|
|
int altrepository=0, obsoletecount, providecount, requirecount,
|
|
filenamecount, dirnamecount, alt_reps_num = 0;
|
|
int_16 *fileflags;
|
|
char **obsoletename, **obsoleteversion,
|
|
**providename, **provideversion,
|
|
**requirename, **requireversion,
|
|
**basename, **dirname, **newversion,
|
|
**fileusername, **filegroupname;
|
|
const char* errstr;
|
|
uint_32 *dirindex, *requireflags, *obsoleteflags, *provideflags;
|
|
#if RPM_VERSION >= 0x050000
|
|
rpmts ts = rpmtsCreate();
|
|
#else
|
|
rpmts ts = NULL;
|
|
#endif
|
|
|
|
repodata[0] = NULL;
|
|
|
|
cleanProvidedListIndex(ct,arch);
|
|
|
|
if (incremental) {
|
|
if (ct->repository[0]) {
|
|
snprintf(scanpath,bufsize,"%sRPMS.%s/",ct->repository[0]->repository_dir,ct->arch[arch]);
|
|
scantag = ct->repository[0]->tag;
|
|
if (ct->repository[0]->repodata_url) {
|
|
repodata[0] = getRepodata(ct->repository[0]->repodata_url,
|
|
ct->arch[arch]);
|
|
if (!repodata[0]) return 1;
|
|
}
|
|
for (i = 1; i <= ct->repository_level; i++) {
|
|
if (ct->repository[i]) {
|
|
altscanpath[i-1] = malloc(bufsize);
|
|
snprintf(altscanpath[i-1], bufsize, "%sRPMS.%s/",ct->repository[i]->repository_dir,ct->arch[arch]);
|
|
altscantag[i-1] = ct->repository[i]->tag;
|
|
if (ct->repository[i]->repodata_url) {
|
|
if (!repodata[0]) {
|
|
logmsg(LOG_ERROR,
|
|
"repodata_url must be defined in main and parent repositories; aborting.");
|
|
return 1;
|
|
}
|
|
repodata[i] = getRepodata(
|
|
ct->repository[i]->repodata_url, ct->arch[arch]);
|
|
if (!repodata[i]) {
|
|
cleanRepodata(repodata[0]);
|
|
return 1;
|
|
}
|
|
}
|
|
alt_reps_num++;
|
|
} else {
|
|
logmsg(LOG_ERROR,"repository[i] not defined; aborting.");
|
|
return 1;
|
|
}
|
|
}
|
|
} else {
|
|
logmsg(LOG_ERROR,"repository[0] is not defined; aborting.");
|
|
return 1;
|
|
}
|
|
} else {
|
|
snprintf(scanpath,bufsize,"%sRPMS.%s/",ct->repository_dir,ct->arch[arch]);
|
|
scantag = ct->tag;
|
|
if (ct->repodata_url) {
|
|
repodata[0] = getRepodata(ct->repodata_url, ct->arch[arch]);
|
|
if (!repodata[0]) return 1;
|
|
}
|
|
}
|
|
|
|
currheaderlist = ct->headerlist[arch];
|
|
|
|
if (repodata[0]) {
|
|
for (i = 0; i <= alt_reps_num; i++) {
|
|
primary_node[i] = xmlDocGetRootElement(repodata[i]->primary_doc)->children;
|
|
filelists_node[i] = xmlDocGetRootElement(repodata[i]->filelists_doc)->children;
|
|
}
|
|
// Setup all repo nodes to first package
|
|
for (i = 0; i <= alt_reps_num; i++)
|
|
currnames[i] = advanceXMLPackageNode(&(primary_node[i]),
|
|
&(filelists_node[i]));
|
|
} else {
|
|
n = scansdir(scanpath, &namelist, rpmselector, scanrpmnamecmp);
|
|
if (n < 0) {
|
|
errstr = strerror(errno);
|
|
logmsg(LOG_ERROR, "%s: cannot scan directory '%s' (%s)", scantag, scanpath, errstr);
|
|
return 1;
|
|
}
|
|
for (i = 0; i < alt_reps_num; i++) {
|
|
altn[i] = scansdir(altscanpath[i], &altnamelist[i], rpmselector, scanrpmnamecmp);
|
|
logmsg(LOG_DEBUG, "%s scan directory is '%s'", altscantag[i], altscanpath[i]);
|
|
if (altn[i] < 0) {
|
|
errstr = strerror(errno);
|
|
logmsg(LOG_ERROR, "%s: cannot scan directory '%s' (%s)", altscantag[i], altscanpath[i], errstr);
|
|
return 1;
|
|
}
|
|
}
|
|
logmsg(LOG_DEBUG, "%s scan directory is '%s'", scantag, scanpath);
|
|
for (i = 0; i < alt_reps_num; i++) {
|
|
altcnt[i]=0;
|
|
}
|
|
}
|
|
|
|
int altidx = -1;
|
|
currname[0] = '\0';
|
|
|
|
while (1) {
|
|
if (repodata[0]) {
|
|
/* Use repodata */
|
|
if (altidx >= 0) {
|
|
// Advance name in repo with current package just done
|
|
free(currnames[altidx]);
|
|
currnames[altidx] = advanceXMLPackageNode(&(primary_node[altidx]),
|
|
&(filelists_node[altidx]));
|
|
}
|
|
altidx = -1;
|
|
nextname[0] = '\0';
|
|
for (i = 0; i <= alt_reps_num; i++) {
|
|
if (currnames[i] &&
|
|
(nextname[0] == '\0' || strcmp(nextname, currnames[i]) >= 0)) {
|
|
strncpy(nextname, currnames[i], bufsize);
|
|
altidx = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (altidx >=0) {
|
|
strncpy(currname, nextname, bufsize);
|
|
//printf("alt%d %s\n", altidx, currname);
|
|
}
|
|
/* clean repodata and break while loop when no more packages are found */
|
|
if (altidx == -1) {
|
|
for (i = 0; i <= alt_reps_num; i++) {
|
|
cleanRepodata(repodata[i]);
|
|
}
|
|
break;
|
|
}
|
|
/* process package */
|
|
newheaderlist = malloc(sizeof(struct headerList));
|
|
if (newheaderlist == NULL) {
|
|
logmsg(LOG_ERROR,"cannot allocate new memory; aborting.\n");
|
|
return 1;
|
|
}
|
|
memset(newheaderlist, 0, sizeof(struct headerList));
|
|
|
|
newheaderlist->name = strdup((char*)
|
|
findXMLPropertyByName(primary_node[altidx], "name")->children->content);
|
|
xmlNode *version = findXMLPropertyByName(primary_node[altidx], "version");
|
|
tmp = (char*)findXMLAttributeByName(version, "epoch");
|
|
newheaderlist->epoch = atoi(tmp);
|
|
free(tmp);
|
|
newheaderlist->version = (char*)findXMLAttributeByName(version, "ver");
|
|
newheaderlist->release = (char*)findXMLAttributeByName(version, "rel");
|
|
newheaderlist->summary = strdup((char*)
|
|
findXMLPropertyByName(primary_node[altidx], "summary")->children->content);
|
|
newheaderlist->arch = strdup((char*)
|
|
findXMLPropertyByName(primary_node[altidx], "arch")->children->content);
|
|
if (findXMLPropertyByName(primary_node[altidx], "description")->children) {
|
|
newheaderlist->description = strdup((char*)
|
|
findXMLPropertyByName(primary_node[altidx], "description")->children->content);
|
|
} else {
|
|
logmsg(LOG_WARNING, "%s(%s, %s): description field is empty",
|
|
newheaderlist->name, newheaderlist->arch, ct->repository[altidx]->tag);
|
|
newheaderlist->description = strdup("");
|
|
}
|
|
xmlNode *format = findXMLPropertyByName(primary_node[altidx], "format");
|
|
newheaderlist->group = strdup((char*)
|
|
findXMLPropertyByName(format, "group")->children->content);
|
|
newheaderlist->sourcename = strdup((char*)
|
|
findXMLPropertyByName(format, "sourcerpm")->children->content);
|
|
xmlNode *psize = findXMLPropertyByName(primary_node[altidx], "size");
|
|
tmp = (char*)findXMLAttributeByName(psize, "package");
|
|
newheaderlist->size = atoi(tmp);
|
|
free(tmp);
|
|
|
|
int ret = addNewToHeaderList(&currheaderlist, newheaderlist, ct,
|
|
altidx, arch);
|
|
|
|
if (ret == 0) {
|
|
getXMLPackageNFV(findXMLPropertyByName(format, "obsoletes"),
|
|
&obsoletename, &obsoleteflags, &obsoleteversion, &obsoletecount);
|
|
getXMLPackageNFV(findXMLPropertyByName(format, "provides"),
|
|
&providename, &provideflags, &provideversion, &providecount);
|
|
getXMLPackageNFV(findXMLPropertyByName(format, "requires"),
|
|
&requirename, &requireflags, &requireversion, &requirecount);
|
|
|
|
newheaderlist->provided = malloc(sizeof(struct providedList*)*providecount);
|
|
for (i=0; i < providecount; i++) {
|
|
provided = findOrCreateProvidedListEntry(
|
|
(struct providedList **) &(ct->providedlist_idx[arch]),
|
|
providename[i],1,arch);
|
|
newheaderlist->provided[i]=provided;
|
|
if (provided && (provided->numproviders == 0)) {
|
|
provided->flags=provideflags[i];
|
|
provided->numproviders++;
|
|
provided->provider=malloc(sizeof(struct headerList*));
|
|
provided->provider[0]=newheaderlist;
|
|
provided->version=malloc(sizeof(char *));
|
|
provided->version[0]=strdup(provideversion[i]);
|
|
} else if (provided && (provided->numproviders > 0)) {
|
|
provided->numproviders++;
|
|
newprovider=malloc(sizeof(struct headerList*)*provided->numproviders);
|
|
for (j = 0; j < provided->numproviders-1; j++) {
|
|
newprovider[j]=provided->provider[j];
|
|
}
|
|
newprovider[provided->numproviders-1] = newheaderlist;
|
|
free(provided->provider);
|
|
provided->provider=newprovider;
|
|
newversion=malloc(sizeof(char *)*provided->numproviders);
|
|
for (j = 0; j < provided->numproviders-1; j++) {
|
|
newversion[j]=provided->version[j];
|
|
}
|
|
newversion[provided->numproviders-1] = strdup(provideversion[i]);
|
|
free(provided->version);
|
|
provided->version=newversion;
|
|
} else {
|
|
fprintf(stderr,"%s has %d providers but is ignored\n",provided->name,provided->numproviders);
|
|
}
|
|
}
|
|
newheaderlist->providename = providename;
|
|
newheaderlist->provideflags = provideflags;
|
|
newheaderlist->provideversion = provideversion;
|
|
newheaderlist->providecount = providecount;
|
|
newheaderlist->obsoletename = obsoletename;
|
|
newheaderlist->obsoleteflags = obsoleteflags;
|
|
newheaderlist->obsoleteversion = obsoleteversion;
|
|
newheaderlist->obsoletecount = obsoletecount;
|
|
newheaderlist->altrepository = altidx;
|
|
// Requires
|
|
newheaderlist->require = malloc(requirecount * sizeof(struct Require *));
|
|
for (j=0; j < requirecount; j++) {
|
|
newheaderlist->require[j] = malloc(sizeof(struct Require));
|
|
newheaderlist->require[j]->name = requirename[j];
|
|
newheaderlist->require[j]->flags = requireflags[j];
|
|
newheaderlist->require[j]->version = requireversion[j];
|
|
newheaderlist->require[j]->resolved = NULL;
|
|
}
|
|
newheaderlist->requirecount = requirecount;
|
|
// Files
|
|
getXMLPackageFiles(filelists_node[altidx], &fileflags, &basename,
|
|
&filenamecount);
|
|
newheaderlist->file = malloc(sizeof(struct fileTree*) * filenamecount);
|
|
newheaderlist->filenamecount = filenamecount;
|
|
for (j=0; j<filenamecount; j++) {
|
|
newheaderlist->file[j] = findOrCreateFileTreeEntry(&ct->filetree[arch], basename[j], arch);
|
|
free(basename[j]);
|
|
//newheaderlist->fileflags[j] = fileflags[j];
|
|
//newheaderlist->fileuser[j] = findOrCreateFileUserListEntry(&ct->fileuserlist[arch], NULL, arch);
|
|
//newheaderlist->filegroup[j] = findOrCreateFileGroupListEntry(&ct->filegrouplist[arch], NULL, arch);
|
|
if (newheaderlist->file[j]->numproviders == 0) {
|
|
newheaderlist->file[j]->numproviders++;
|
|
newheaderlist->file[j]->provider=malloc(sizeof(struct headerList*));
|
|
newheaderlist->file[j]->provider[0]=newheaderlist;
|
|
} else {
|
|
// check if the package is already providing it...
|
|
for (k = 0; k < newheaderlist->file[j]->numproviders; k++) {
|
|
if (newheaderlist->file[j]->provider[k] == newheaderlist)
|
|
break;
|
|
}
|
|
// if not add to the list of providers
|
|
if (k == newheaderlist->file[j]->numproviders) {
|
|
newheaderlist->file[j]->numproviders++;
|
|
newprovider=malloc(
|
|
sizeof(struct headerList*)*newheaderlist->file[j]->numproviders);
|
|
for (k = 0; k < newheaderlist->file[j]->numproviders-1; k++) {
|
|
newprovider[k]=newheaderlist->file[j]->provider[k];
|
|
}
|
|
newprovider[newheaderlist->file[j]->numproviders-1] = newheaderlist;
|
|
free(newheaderlist->file[j]->provider);
|
|
newheaderlist->file[j]->provider=newprovider;
|
|
}
|
|
}
|
|
}
|
|
free(basename);
|
|
free(fileflags);
|
|
}
|
|
|
|
} else {
|
|
/* Scan packages from local directories */
|
|
/* check for duplicates in main repository */
|
|
if ((cnt < n - 1) &&
|
|
(!rpmnamecmp(namelist[cnt]->d_name,namelist[cnt+1]->d_name,0))) {
|
|
logmsg(LOG_WARNING, "%s: duplicated RPM package in %s repository (skipped)",namelist[cnt]->d_name, scantag);
|
|
cnt++;
|
|
}
|
|
/* find next package in all repositories */
|
|
if (cnt < n) {
|
|
strncpy(currname, namelist[cnt]->d_name, bufsize);
|
|
} else {
|
|
currname[0] = '\0';
|
|
}
|
|
for (i = 0; i < alt_reps_num; i++) {
|
|
/* scan alternate repositories to find any package which comes first according to name sorting */
|
|
if ((altcnt[i] < altn[i]) &&
|
|
((rpmnamecmp(currname, altnamelist[i][altcnt[i]]->d_name,0) >= 0) || (currname[0] == '\0'))) {
|
|
strncpy(currname, altnamelist[i][altcnt[i]]->d_name,bufsize);
|
|
}
|
|
}
|
|
|
|
if (cnt < n && (rpmnamecmp(currname, namelist[cnt]->d_name, 0) == 0)) {
|
|
/* selected package exists in base repository */
|
|
memcpy(filepath, scanpath, strlen(scanpath) + 1);
|
|
filename=&filepath[strlen(scanpath)];
|
|
strncpy(filename, namelist[cnt]->d_name,bufsize-strlen(scanpath));
|
|
altrepository=0;
|
|
cnt++;
|
|
} else {
|
|
for (i = 0; i < alt_reps_num; i++) {
|
|
if ((altcnt[i] < altn[i]) &&
|
|
(strncmp(currname, altnamelist[i][altcnt[i]]->d_name, bufsize) == 0)) {
|
|
/* selected package exists in this repository */
|
|
memcpy(filepath, altscanpath[i], strlen(altscanpath[i]) + 1);
|
|
filename=&filepath[strlen(altscanpath[i])];
|
|
strncpy(filename, (altnamelist[i])[altcnt[i]]->d_name, bufsize-strlen(altscanpath[i]));
|
|
altrepository=i+1;
|
|
altcnt[i]++;
|
|
/* check for duplicates in alternate repository */
|
|
if ((altcnt[i] < altn[i] - 1) &&
|
|
(!rpmnamecmp(altnamelist[i][altcnt[i]]->d_name,altnamelist[i][altcnt[i]+1]->d_name,0))) {
|
|
if (i == ct->repository_level-1) {
|
|
logmsg(LOG_WARNING, "%s: duplicated RPM package (skipped)",
|
|
altnamelist[i][altcnt[i]]->d_name, altscantag[i]);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/* break while loop when no more packages are found */
|
|
if (currname[0] == '\0') { break; }
|
|
/* process package */
|
|
logmsg(LOG_DEBUG, "getting header for %s", filepath);
|
|
|
|
if (getHeader(&ts, filepath, &h)) {
|
|
errstr = strerror(errno);
|
|
logmsg(LOG_WARNING,
|
|
"%s: unable to read header (%s); skipping.",filename, errstr);
|
|
} else {
|
|
getPackageObsoletes(h, &obsoletename, &obsoleteflags,
|
|
&obsoleteversion, &obsoletecount);
|
|
getPackageProvides(h, &providename, &provideflags,
|
|
&provideversion, &providecount);
|
|
getPackageRequires(h, &requirename, &requireflags,
|
|
&requireversion, &requirecount);
|
|
getPackageFiles(h, &dirindex, &dirname, &dirnamecount,
|
|
&basename, &filenamecount,
|
|
&fileusername, &filegroupname, &fileflags);
|
|
|
|
newheaderlist = malloc(sizeof(struct headerList));
|
|
if (newheaderlist == NULL) {
|
|
logmsg(LOG_ERROR,"cannot allocate new memory; aborting.\n");
|
|
return 1;
|
|
}
|
|
memset(newheaderlist, 0, sizeof(struct headerList));
|
|
getPackageInfoIntoHeaderList(h, newheaderlist);
|
|
|
|
int ret = addNewToHeaderList(&currheaderlist, newheaderlist, ct,
|
|
altrepository, arch);
|
|
|
|
if (ret == 0) {
|
|
newheaderlist->provided = malloc(sizeof(struct providedList*)*providecount);
|
|
for (i=0; i < providecount; i++) {
|
|
provided = findOrCreateProvidedListEntry(
|
|
(struct providedList **) &(ct->providedlist_idx[arch]),
|
|
providename[i],1,arch);
|
|
newheaderlist->provided[i]=provided;
|
|
if (provided && (provided->numproviders == 0)) {
|
|
provided->flags=provideflags[i];
|
|
provided->numproviders++;
|
|
provided->provider=malloc(sizeof(struct headerList*));
|
|
provided->provider[0]=newheaderlist;
|
|
provided->version=malloc(sizeof(char *));
|
|
provided->version[0]=strdup(provideversion[i]);
|
|
} else if (provided && (provided->numproviders > 0)) {
|
|
provided->numproviders++;
|
|
newprovider=malloc(sizeof(struct headerList*)*provided->numproviders);
|
|
for (j = 0; j < provided->numproviders-1; j++) {
|
|
newprovider[j]=provided->provider[j];
|
|
}
|
|
newprovider[provided->numproviders-1] = newheaderlist;
|
|
free(provided->provider);
|
|
provided->provider=newprovider;
|
|
|
|
newversion=malloc(sizeof(char *)*provided->numproviders);
|
|
for (j = 0; j < provided->numproviders-1; j++) {
|
|
newversion[j]=provided->version[j];
|
|
}
|
|
newversion[provided->numproviders-1] = strdup(provideversion[i]);
|
|
free(provided->version);
|
|
provided->version=newversion;
|
|
} else {
|
|
fprintf(stderr,"%s has %d providers but is ignored\n",provided->name,provided->numproviders);
|
|
}
|
|
}
|
|
newheaderlist->providename = providename;
|
|
newheaderlist->provideflags = provideflags;
|
|
newheaderlist->provideversion = provideversion;
|
|
newheaderlist->providecount = providecount;
|
|
newheaderlist->obsoletename = obsoletename;
|
|
newheaderlist->obsoleteflags = obsoleteflags;
|
|
newheaderlist->obsoleteversion = obsoleteversion;
|
|
newheaderlist->obsoletecount = obsoletecount;
|
|
newheaderlist->altrepository = altrepository;
|
|
newheaderlist->require = malloc(requirecount * sizeof(struct Require *));
|
|
for (j=0; j < requirecount; j++) {
|
|
newheaderlist->require[j] = malloc(sizeof(struct Require));
|
|
newheaderlist->require[j]->name = requirename[j];
|
|
newheaderlist->require[j]->flags = requireflags[j];
|
|
newheaderlist->require[j]->version = requireversion[j];
|
|
newheaderlist->require[j]->resolved = NULL;
|
|
}
|
|
newheaderlist->requirecount = requirecount;
|
|
newheaderlist->file =
|
|
malloc(sizeof(struct fileTree*) * filenamecount);
|
|
newheaderlist->fileflags =
|
|
malloc(sizeof(int_16 *) * filenamecount);
|
|
newheaderlist->fileuser =
|
|
malloc(sizeof(struct fileUserList *) * filenamecount);
|
|
newheaderlist->filegroup =
|
|
malloc(sizeof(char *) * filenamecount);
|
|
for (j=0; j<filenamecount; j++) {
|
|
snprintf(filename,bufsize,"%s%s",dirname[dirindex[j]],basename[j]);
|
|
newheaderlist->file[j] = findOrCreateFileTreeEntry(&ct->filetree[arch], filename, arch);
|
|
newheaderlist->fileflags[j] = fileflags[j];
|
|
newheaderlist->fileuser[j] = findOrCreateFileUserListEntry(&ct->fileuserlist[arch], fileusername[j], arch);
|
|
free(fileusername[j]);
|
|
newheaderlist->filegroup[j] = findOrCreateFileGroupListEntry(&ct->filegrouplist[arch], filegroupname[j], arch);
|
|
free(filegroupname[j]);
|
|
if (newheaderlist->file[j]->numproviders == 0) {
|
|
newheaderlist->file[j]->numproviders++;
|
|
newheaderlist->file[j]->provider=malloc(sizeof(struct headerList*));
|
|
newheaderlist->file[j]->provider[0]=newheaderlist;
|
|
} else {
|
|
/* check if the package is already providing it... */
|
|
for (k = 0; k < newheaderlist->file[j]->numproviders; k++) {
|
|
if (newheaderlist->file[j]->provider[k] == newheaderlist)
|
|
break;
|
|
}
|
|
/* if not add to the list of providers */
|
|
if (k == newheaderlist->file[j]->numproviders) {
|
|
newheaderlist->file[j]->numproviders++;
|
|
newprovider=malloc(
|
|
sizeof(struct headerList*)*newheaderlist->file[j]->numproviders);
|
|
for (k = 0; k < newheaderlist->file[j]->numproviders-1; k++) {
|
|
newprovider[k]=newheaderlist->file[j]->provider[k];
|
|
}
|
|
newprovider[newheaderlist->file[j]->numproviders-1] = newheaderlist;
|
|
free(newheaderlist->file[j]->provider);
|
|
newheaderlist->file[j]->provider=newprovider;
|
|
}
|
|
}
|
|
}
|
|
newheaderlist->filenamecount = filenamecount;
|
|
}
|
|
(void) headerFree(h);
|
|
} // if getHeader()
|
|
if (altrepository > 0)
|
|
free(altnamelist[altrepository-1][altcnt[altrepository-1]-1]);
|
|
else free(namelist[cnt-1]);
|
|
}
|
|
} // main while
|
|
#if RPM_VERSION >= 0x050000
|
|
rpmtsFree(ts);
|
|
#endif
|
|
if (!repodata[0])
|
|
free(namelist);
|
|
createProvidedListIndex((struct providedList **)&(ct->providedlist_idx[arch]), arch);
|
|
return 0;
|
|
}
|