562 lines
13 KiB
C
562 lines
13 KiB
C
#include <alloca.h>
|
|
#include <ctype.h>
|
|
#include <dirent.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <sys/stat.h>
|
|
#include <glob.h>
|
|
#include <dirent.h>
|
|
#include <popt.h>
|
|
#include <rpmlib.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <rpm/misc.h>
|
|
#include <rpm/rpmts.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
|
|
#include "hash.h"
|
|
|
|
#define FILENAME_TAG 1000000
|
|
#define FILESIZE_TAG 1000001
|
|
#define CDNUM_TAG 1000002
|
|
#define ORDER_TAG 1000003
|
|
#define MATCHER_TAG 1000004
|
|
|
|
void expandFilelist(Header h);
|
|
void compressFilelist(Header h);
|
|
|
|
struct onePackageInfo {
|
|
char * name;
|
|
char * arch;
|
|
};
|
|
|
|
int pkgInfoCmp(const void * a, const void * b) {
|
|
const struct onePackageInfo * one = a;
|
|
const struct onePackageInfo * two = b;
|
|
int i;
|
|
|
|
i = strcmp(one->name, two->name);
|
|
if (i) return i;
|
|
|
|
return strcmp(one->arch, two->arch);
|
|
}
|
|
|
|
/*int tagsInList2[] = {
|
|
RPMTAG_FILESIZES, RPMTAG_FILEMODES, RPMTAG_FILEMD5S, RPMTAG_FILELINKTOS,
|
|
RPMTAG_FILEFLAGS, RPMTAG_FILELANGS,
|
|
RPMTAG_DIRNAMES, RPMTAG_DIRINDEXES, RPMTAG_BASENAMES,
|
|
-1
|
|
};*/
|
|
int tagsInList2[] = { -1 };
|
|
|
|
struct onePackageInfo * pkgList;
|
|
int pkgListItems = 0;
|
|
int pkgListAlloced = 0;
|
|
char ** depOrder = NULL;
|
|
hashTable requireTable;
|
|
|
|
/* make sure its <package>-<version>-<release> */
|
|
int sanityCheckDepOrderLine(char *line) {
|
|
char *r, *v;
|
|
|
|
|
|
r = strrchr(line, '-');
|
|
if (!r)
|
|
return -1;
|
|
|
|
v = strrchr(r, '-');
|
|
if (!v)
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/* mmmm... linear search */
|
|
int getOrder (char * fn)
|
|
{
|
|
char *p;
|
|
int i;
|
|
|
|
if (!depOrder || !depOrder[0] || !depOrder[0][0]) {
|
|
return -1;
|
|
}
|
|
|
|
i = 0;
|
|
p = depOrder[i];
|
|
while (p && *p && strncmp (fn, p, strlen(p))) {
|
|
p = depOrder[++i];
|
|
}
|
|
|
|
if (p) {
|
|
return i;
|
|
}
|
|
|
|
fprintf (stderr, "WARNING: ordering not found for %s\n", fn);
|
|
|
|
return -1;
|
|
}
|
|
|
|
int onePrePass(const char * dirName) {
|
|
struct dirent * ent;
|
|
DIR * dir;
|
|
char * subdir = alloca(strlen(dirName) + 20);
|
|
FD_t fd;
|
|
int rc;
|
|
Header h;
|
|
char ** requires;
|
|
int c;
|
|
rpmts ts = rpmtsCreate();
|
|
rpmtsSetRootDir(ts, "/");
|
|
rpmtsSetVSFlags(ts, ~RPMVSF_NOHDRCHK);
|
|
rpmtsCloseDB(ts);
|
|
|
|
sprintf(subdir, "%s/RedHat/RPMS", dirName);
|
|
|
|
dir = opendir(subdir);
|
|
if (!dir) {
|
|
fprintf(stderr,"error opening directory %s: %s\n", subdir,
|
|
strerror(errno));
|
|
return 1;
|
|
}
|
|
|
|
chdir(subdir);
|
|
|
|
errno = 0;
|
|
ent = readdir(dir);
|
|
if (errno) {
|
|
perror("readdir");
|
|
return 1;
|
|
}
|
|
|
|
while (ent) {
|
|
int i = strlen (ent->d_name);
|
|
|
|
if (i > 4 && strcasecmp (&ent->d_name [i - 4], ".rpm") == 0) {
|
|
fd = Fopen(ent->d_name, "r");
|
|
|
|
if (!fd) {
|
|
perror("open");
|
|
exit(1);
|
|
}
|
|
|
|
rc = rpmReadPackageFile(ts, fd, ent->d_name, &h);
|
|
|
|
if (!rc) {
|
|
if (headerGetEntry(h, RPMTAG_REQUIRENAME, NULL,
|
|
(void **) &requires, &c)) {
|
|
while (c--)
|
|
if (*requires[c] == '/')
|
|
htAddToTable(requireTable, requires[c], ".");
|
|
}
|
|
|
|
headerFree(h);
|
|
/* XXX free requires */
|
|
}
|
|
|
|
Fclose(fd);
|
|
}
|
|
|
|
errno = 0;
|
|
ent = readdir(dir);
|
|
if (errno) {
|
|
perror("readdir");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
closedir(dir);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int onePass(FD_t outfd, FD_t out2fd, const char * dirName, int cdNum) {
|
|
FD_t fd;
|
|
struct dirent * ent;
|
|
char * subdir = alloca(strlen(dirName) + 20);
|
|
int errno;
|
|
Header h, nh, h2;
|
|
int rc;
|
|
int_32 size;
|
|
DIR * dir;
|
|
struct stat sb;
|
|
int_32 * fileSizes;
|
|
int fileCount;
|
|
int order = -1;
|
|
char ** newFileList, ** fileNames;
|
|
uint_32 * newFileFlags, * fileFlags;
|
|
int newFileListCount;
|
|
int marker = time(NULL); /* good enough counter; we'll increment it */
|
|
rpmts ts = rpmtsCreate();
|
|
rpmtsSetRootDir(ts, "/");
|
|
rpmtsSetVSFlags(ts, ~RPMVSF_NOHDRCHK);
|
|
rpmtsCloseDB(ts);
|
|
|
|
sprintf(subdir, "%s/RedHat/RPMS", dirName);
|
|
|
|
dir = opendir(subdir);
|
|
if (!dir) {
|
|
fprintf(stderr,"error opening directory %s: %s\n", subdir,
|
|
strerror(errno));
|
|
return 1;
|
|
}
|
|
|
|
chdir(subdir);
|
|
|
|
errno = 0;
|
|
ent = readdir(dir);
|
|
if (errno) {
|
|
perror("readdir");
|
|
return 1;
|
|
}
|
|
|
|
while (ent) {
|
|
int i = strlen (ent->d_name);
|
|
if (i > 4 && strcasecmp (&ent->d_name [i - 4], ".rpm") == 0) {
|
|
fd = Fopen(ent->d_name, "r");
|
|
|
|
if (!fd) {
|
|
perror("open");
|
|
exit(1);
|
|
}
|
|
|
|
if (stat(ent->d_name, &sb)) {
|
|
perror("stat");
|
|
exit(1);
|
|
}
|
|
size = sb.st_size;
|
|
|
|
rc = rpmReadPackageFile(ts, fd, ent->d_name, &h);
|
|
|
|
if (!rc) {
|
|
if (pkgListItems == pkgListAlloced) {
|
|
pkgListAlloced += 100;
|
|
pkgList = realloc(pkgList,
|
|
sizeof(*pkgList) * pkgListAlloced);
|
|
}
|
|
|
|
headerGetEntry(h, RPMTAG_NAME, NULL,
|
|
(void **) &pkgList[pkgListItems].name, NULL);
|
|
headerGetEntry(h, RPMTAG_ARCH, NULL,
|
|
(void **) &pkgList[pkgListItems].arch, NULL);
|
|
|
|
pkgList[pkgListItems].name = strdup(pkgList[pkgListItems].name);
|
|
pkgList[pkgListItems].arch = strdup(pkgList[pkgListItems].arch);
|
|
pkgListItems++;
|
|
|
|
headerRemoveEntry(h, RPMTAG_POSTIN);
|
|
headerRemoveEntry(h, RPMTAG_POSTUN);
|
|
headerRemoveEntry(h, RPMTAG_PREIN);
|
|
headerRemoveEntry(h, RPMTAG_PREUN);
|
|
headerRemoveEntry(h, RPMTAG_FILEUSERNAME);
|
|
headerRemoveEntry(h, RPMTAG_FILEGROUPNAME);
|
|
headerRemoveEntry(h, RPMTAG_FILEVERIFYFLAGS);
|
|
headerRemoveEntry(h, RPMTAG_FILERDEVS);
|
|
headerRemoveEntry(h, RPMTAG_FILEMTIMES);
|
|
headerRemoveEntry(h, RPMTAG_FILEDEVICES);
|
|
headerRemoveEntry(h, RPMTAG_FILEINODES);
|
|
headerRemoveEntry(h, RPMTAG_TRIGGERSCRIPTS);
|
|
headerRemoveEntry(h, RPMTAG_TRIGGERVERSION);
|
|
headerRemoveEntry(h, RPMTAG_TRIGGERFLAGS);
|
|
headerRemoveEntry(h, RPMTAG_TRIGGERNAME);
|
|
headerRemoveEntry(h, RPMTAG_CHANGELOGTIME);
|
|
headerRemoveEntry(h, RPMTAG_CHANGELOGNAME);
|
|
headerRemoveEntry(h, RPMTAG_CHANGELOGTEXT);
|
|
headerRemoveEntry(h, RPMTAG_ICON);
|
|
headerRemoveEntry(h, RPMTAG_GIF);
|
|
headerRemoveEntry(h, RPMTAG_VENDOR);
|
|
headerRemoveEntry(h, RPMTAG_EXCLUDE);
|
|
headerRemoveEntry(h, RPMTAG_EXCLUSIVE);
|
|
headerRemoveEntry(h, RPMTAG_DISTRIBUTION);
|
|
headerRemoveEntry(h, RPMTAG_VERIFYSCRIPT);
|
|
|
|
/* new header sigs */
|
|
headerRemoveEntry(h, RPMTAG_SIGSIZE);
|
|
headerRemoveEntry(h, RPMTAG_SIGGPG);
|
|
headerRemoveEntry(h, RPMTAG_SIGPGP);
|
|
|
|
/* other stuff we don't need - msw */
|
|
headerRemoveEntry(h, RPMTAG_PACKAGER);
|
|
headerRemoveEntry(h, RPMTAG_LICENSE);
|
|
headerRemoveEntry(h, RPMTAG_BUILDTIME);
|
|
headerRemoveEntry(h, RPMTAG_BUILDHOST);
|
|
headerRemoveEntry(h, RPMTAG_RPMVERSION);
|
|
headerRemoveEntry(h, RPMTAG_POSTINPROG);
|
|
headerRemoveEntry(h, RPMTAG_POSTUNPROG);
|
|
headerRemoveEntry(h, RPMTAG_PREINPROG);
|
|
headerRemoveEntry(h, RPMTAG_PREUNPROG);
|
|
headerRemoveEntry(h, RPMTAG_COOKIE);
|
|
headerRemoveEntry(h, RPMTAG_OPTFLAGS);
|
|
headerRemoveEntry(h, RPMTAG_PAYLOADFORMAT);
|
|
headerRemoveEntry(h, RPMTAG_PAYLOADCOMPRESSOR);
|
|
headerRemoveEntry(h, RPMTAG_PAYLOADFLAGS);
|
|
|
|
headerAddEntry(h, FILENAME_TAG, RPM_STRING_TYPE, ent->d_name, 1);
|
|
headerAddEntry(h, FILESIZE_TAG, RPM_INT32_TYPE,
|
|
&size, 1);
|
|
|
|
/* Recaclulate the package size based on a 4k block size */
|
|
if (headerGetEntry(h, RPMTAG_FILESIZES, NULL,
|
|
(void **) &fileSizes, &fileCount)) {
|
|
int fileNum;
|
|
int newSize = 0;
|
|
int * p;
|
|
|
|
for (fileNum = 0; fileNum < fileCount; fileNum++)
|
|
newSize += ((fileSizes[fileNum] + 4093) / 4096) * 4096;
|
|
|
|
headerGetEntry(h, RPMTAG_SIZE, NULL, (void **) &p, NULL);
|
|
|
|
headerRemoveEntry(h, RPMTAG_SIZE);
|
|
headerAddEntry(h, RPMTAG_SIZE, RPM_INT32_TYPE,
|
|
&newSize, 1);
|
|
}
|
|
|
|
if (cdNum > -1)
|
|
headerAddEntry(h, CDNUM_TAG, RPM_INT32_TYPE,
|
|
&cdNum, 1);
|
|
|
|
if ((order = getOrder (ent->d_name)) > -1) {
|
|
headerAddEntry(h, ORDER_TAG, RPM_INT32_TYPE,
|
|
&order, 1);
|
|
}
|
|
|
|
expandFilelist(h);
|
|
newFileList = NULL;
|
|
if (headerGetEntry(h, RPMTAG_OLDFILENAMES, NULL,
|
|
(void **) &fileNames, &fileCount)) {
|
|
headerGetEntry(h, RPMTAG_FILEFLAGS, NULL,
|
|
(void **) &fileFlags, NULL);
|
|
|
|
newFileList = malloc(sizeof(*newFileList) * fileCount);
|
|
newFileFlags = malloc(sizeof(*newFileList) * fileCount);
|
|
newFileListCount = 0;
|
|
|
|
for (i = 0; i < fileCount; i++) {
|
|
if (htInTable(requireTable, fileNames[i], ".")) {
|
|
newFileList[newFileListCount] = strdup(fileNames[i]);
|
|
newFileFlags[newFileListCount] = fileFlags[i];
|
|
newFileListCount++;
|
|
}
|
|
}
|
|
|
|
if (!newFileListCount) {
|
|
free(newFileList);
|
|
free(newFileFlags);
|
|
newFileList = NULL;
|
|
}
|
|
|
|
/* XXX free fileNames */
|
|
}
|
|
compressFilelist(h);
|
|
|
|
h2 = headerNew();
|
|
for (i = 0; tagsInList2[i] > -1; i++) {
|
|
int_32 type, c;
|
|
void * p;
|
|
|
|
if (headerGetEntry(h, tagsInList2[i], &type, &p, &c)) {
|
|
headerAddEntry(h2, tagsInList2[i], type, p, c);
|
|
headerRemoveEntry(h, tagsInList2[i]);
|
|
}
|
|
|
|
/* XXX need to headerFreeData */
|
|
}
|
|
|
|
if (newFileList) {
|
|
headerAddEntry(h, RPMTAG_OLDFILENAMES,
|
|
RPM_STRING_ARRAY_TYPE,
|
|
newFileList, newFileListCount);
|
|
headerAddEntry(h, RPMTAG_FILEFLAGS,
|
|
RPM_INT32_TYPE,
|
|
&newFileFlags, newFileListCount);
|
|
|
|
compressFilelist(h);
|
|
while (newFileListCount--) {
|
|
free(newFileList[newFileListCount]);
|
|
}
|
|
free(newFileList);
|
|
free(newFileFlags);
|
|
newFileList = NULL;
|
|
}
|
|
|
|
headerAddEntry(h, MATCHER_TAG, RPM_INT32_TYPE, &marker, 1);
|
|
headerAddEntry(h2, MATCHER_TAG, RPM_INT32_TYPE, &marker, 1);
|
|
marker++;
|
|
|
|
nh = headerCopy (h);
|
|
headerWrite(outfd, nh, HEADER_MAGIC_YES);
|
|
headerWrite(out2fd, h2, HEADER_MAGIC_YES);
|
|
|
|
headerFree(h);
|
|
headerFree(nh);
|
|
headerFree(h2);
|
|
}
|
|
|
|
Fclose(fd);
|
|
}
|
|
|
|
errno = 0;
|
|
ent = readdir(dir);
|
|
if (errno) {
|
|
perror("readdir");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
closedir(dir);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void usage(void) {
|
|
fprintf(stderr, "genhdlist: genhdlist [--withnumbers] [--fileorder <path>] [--hdlist <path>] <paths>+\n");
|
|
exit(1);
|
|
}
|
|
|
|
int main(int argc, const char ** argv) {
|
|
char buf[300];
|
|
FD_t outfd, out2fd;
|
|
int cdNum = -1;
|
|
const char ** args;
|
|
int doNumber = 0;
|
|
int rc;
|
|
int i;
|
|
char * hdListFile = NULL;
|
|
char * hdListFile2 = NULL;
|
|
char * depOrderFile = NULL;
|
|
poptContext optCon;
|
|
struct poptOption options[] = {
|
|
{ "hdlist", '\0', POPT_ARG_STRING, &hdListFile, 0 },
|
|
{ "withnumbers", '\0', 0, &doNumber, 0 },
|
|
{ "fileorder", '\0', POPT_ARG_STRING, &depOrderFile, 0 },
|
|
{ 0, 0, 0, 0, 0 }
|
|
};
|
|
|
|
optCon = poptGetContext("genhdlist", argc, argv, options, 0);
|
|
poptReadDefaultConfig(optCon, 1);
|
|
|
|
if ((rc = poptGetNextOpt(optCon)) < -1) {
|
|
fprintf(stderr, "%s: bad argument %s: %s\n", "genhdlist",
|
|
poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
|
|
poptStrerror(rc));
|
|
return 1;
|
|
}
|
|
|
|
args = poptGetArgs(optCon);
|
|
if (!args || !args[0] || !args[0][0])
|
|
usage();
|
|
|
|
if (depOrderFile) {
|
|
FILE *f;
|
|
int nalloced = 0;
|
|
int numpkgs = 0;
|
|
int len = 0;
|
|
char b[80];
|
|
|
|
if (!(f = fopen(depOrderFile, "r"))) {
|
|
fprintf (stderr, "Unable to read %s\n", depOrderFile);
|
|
usage();
|
|
}
|
|
|
|
while ((fgets(b, sizeof(b) - 1, f))) {
|
|
if (numpkgs == nalloced) {
|
|
depOrder = realloc (depOrder, sizeof (char *) * (nalloced + 6));
|
|
memset (depOrder + numpkgs, '\0', sizeof (char *) * 6);
|
|
nalloced += 5;
|
|
}
|
|
|
|
len = strlen(b);
|
|
/* chop */
|
|
b[--len] = '\0';
|
|
|
|
/* sanity check */
|
|
/* should have the format of a <package name>-<version>-<release> */
|
|
if (sanityCheckDepOrderLine(b)) {
|
|
fprintf(stderr, "genhdlist: FATAL ERROR -> \"%s\" is not a package name!!\n",b);
|
|
fprintf(stderr, "Your package list file %s is most likely CORRUPT!\n", depOrderFile);
|
|
exit(1);
|
|
}
|
|
|
|
depOrder[numpkgs] = malloc (len + 1);
|
|
strcpy (depOrder[numpkgs], b);
|
|
numpkgs++;
|
|
}
|
|
depOrder[numpkgs] = NULL; /* end with a null */
|
|
}
|
|
|
|
requireTable = htNewTable(1000);
|
|
|
|
if (!hdListFile) {
|
|
strcpy(buf, args[0]);
|
|
strcat(buf, "/RedHat/base/hdlist");
|
|
hdListFile = buf;
|
|
}
|
|
|
|
unlink(hdListFile);
|
|
|
|
hdListFile2 = malloc(strlen(hdListFile) + 2);
|
|
sprintf(hdListFile2, "%s2", hdListFile);
|
|
|
|
unlink (hdListFile);
|
|
unlink (hdListFile2);
|
|
|
|
outfd = Fopen(hdListFile, "w");
|
|
if (!outfd) {
|
|
fprintf(stderr,"error creating file %s: %s\n", hdListFile,
|
|
strerror(errno));
|
|
return 1;
|
|
}
|
|
|
|
out2fd = Fopen(hdListFile2, "w");
|
|
if (!out2fd) {
|
|
fprintf(stderr,"error creating file %s: %s\n", hdListFile2,
|
|
strerror(errno));
|
|
return 1;
|
|
}
|
|
|
|
if (doNumber)
|
|
cdNum = 1;
|
|
|
|
/* if (args > 1 && !doNumber) { */
|
|
/* fprintf(stderr, "error: building hdlist for multiple trees without numbers\n"); */
|
|
/* exit(1); */
|
|
/* } */
|
|
|
|
i = 0;
|
|
while (args[i]) {
|
|
if (onePrePass(args[i]))
|
|
return 1;
|
|
i++;
|
|
}
|
|
|
|
i = 0;
|
|
while (args[i]) {
|
|
if (onePass(outfd, out2fd, args[i], cdNum))
|
|
return 1;
|
|
if (doNumber) cdNum++;
|
|
i++;
|
|
}
|
|
|
|
Fclose(outfd);
|
|
Fclose(out2fd);
|
|
|
|
poptFreeContext(optCon);
|
|
|
|
qsort(pkgList, pkgListItems, sizeof(*pkgList), pkgInfoCmp);
|
|
rc = 0;
|
|
for (i = 1; i < pkgListItems; i++) {
|
|
if (!pkgInfoCmp(pkgList + i - 1, pkgList + i)) {
|
|
fprintf(stderr, "duplicate package for %s on %s\n",
|
|
pkgList[i].name, pkgList[i].arch);
|
|
rc = 1;
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|