--- /dev/null
+#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;
+}