Create.
authorjbj <devnull@localhost>
Fri, 16 May 2003 21:17:31 +0000 (21:17 +0000)
committerjbj <devnull@localhost>
Fri, 16 May 2003 21:17:31 +0000 (21:17 +0000)
CVS patchset: 6850
CVS date: 2003/05/16 21:17:31

tools/genhdlist.c [new file with mode: 0644]

diff --git a/tools/genhdlist.c b/tools/genhdlist.c
new file mode 100644 (file)
index 0000000..9f9627f
--- /dev/null
@@ -0,0 +1,561 @@
+#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;
+}