/* * distromatic - tool for RPM based repositories * * Copyright (C) 2004-2021 by Silvan Calarco * Copyright (C) 2006 by Davide Madrisan * * 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 #include #include #include #include #ifndef H_RPMLIB # include #endif #if RPM_VERSION >= 0x040100 #include #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 # endif # include #endif #if HAVE_STRINGS_H # include #endif #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #include "distromatic.h" #include "config.h" #include "changelog.h" #include "functions.h" #include "headerlist.h" #include "rpmfunctions.h" #include #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; jfile[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; jfile[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; }